From f16d5983a5d5568258672ccc1eef6cf131235245 Mon Sep 17 00:00:00 2001 From: Thomas Schmelzer Date: Thu, 2 Apr 2026 10:26:19 +0400 Subject: [PATCH 1/4] Update ref version to v0.8.20 and add renovate template --- .rhiza/template.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.rhiza/template.yml b/.rhiza/template.yml index 41b2154..1ffdf97 100644 --- a/.rhiza/template.yml +++ b/.rhiza/template.yml @@ -1,9 +1,9 @@ repository: "jebel-quant/rhiza" -ref: "v0.8.16" +ref: "v0.8.20" templates: - github - tests - legal - book - + - renovate From 48c04452cef54cfcbbc845f95b4632128d8a7b61 Mon Sep 17 00:00:00 2001 From: Thomas Schmelzer Date: Thu, 2 Apr 2026 10:27:46 +0400 Subject: [PATCH 2/4] sync --- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/renovate_rhiza_sync.yml | 84 ---------- .github/workflows/rhiza_book.yml | 4 +- .github/workflows/rhiza_ci.yml | 172 ++++++++++++++++++-- .github/workflows/rhiza_dep_compat_test.yml | 56 ------- .github/workflows/rhiza_deptry.yml | 48 ------ .github/workflows/rhiza_license.yml | 45 ----- .github/workflows/rhiza_pip_audit.yml | 25 --- .github/workflows/rhiza_pre-commit.yml | 52 ------ .github/workflows/rhiza_release.yml | 18 +- .github/workflows/rhiza_security.yml | 46 ------ .github/workflows/rhiza_semgrep.yml | 48 ------ .github/workflows/rhiza_sync.yml | 104 ++++++++++-- .github/workflows/rhiza_typecheck.yml | 50 ------ .github/workflows/rhiza_validate.yml | 35 ---- .github/workflows/rhiza_weekly.yml | 118 ++++++++++++++ .gitignore | 8 + .pre-commit-config.yaml | 9 +- .rhiza/make.d/quality.mk | 15 +- .semgrep.yml => .rhiza/semgrep.yml | 0 .rhiza/template.lock | 22 +-- .rhiza/tests/api/test_makefile_targets.py | 21 +++ .rhiza/tests/integration/test_marimushka.py | 93 ----------- Makefile | 17 +- docs/CUSTOMIZATION.md | 2 +- renovate.json | 57 +++++++ 26 files changed, 511 insertions(+), 640 deletions(-) delete mode 100644 .github/workflows/renovate_rhiza_sync.yml delete mode 100644 .github/workflows/rhiza_dep_compat_test.yml delete mode 100644 .github/workflows/rhiza_deptry.yml delete mode 100644 .github/workflows/rhiza_license.yml delete mode 100644 .github/workflows/rhiza_pip_audit.yml delete mode 100644 .github/workflows/rhiza_pre-commit.yml delete mode 100644 .github/workflows/rhiza_security.yml delete mode 100644 .github/workflows/rhiza_semgrep.yml delete mode 100644 .github/workflows/rhiza_typecheck.yml delete mode 100644 .github/workflows/rhiza_validate.yml create mode 100644 .github/workflows/rhiza_weekly.yml rename .semgrep.yml => .rhiza/semgrep.yml (100%) delete mode 100644 .rhiza/tests/integration/test_marimushka.py create mode 100644 renovate.json diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 86d56a6..55c42e5 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -34,7 +34,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7.6.0 with: - version: "0.10.12" + version: "0.11.2" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth diff --git a/.github/workflows/renovate_rhiza_sync.yml b/.github/workflows/renovate_rhiza_sync.yml deleted file mode 100644 index 26e91c7..0000000 --- a/.github/workflows/renovate_rhiza_sync.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Rhiza Template Sync -# Automatically sync rhiza template files when Renovate updates .rhiza/template.yml - -on: - push: - branches: - - 'renovate/jebel-quant-rhiza-**' - - 'rhiza/**' - paths: - - '.rhiza/template.yml' - -permissions: - contents: write - -jobs: - sync-template: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - ref: ${{ github.ref }} - token: ${{ secrets.PAT_TOKEN || github.token }} - - - name: Check PAT_TOKEN configuration - shell: bash - env: - PAT_TOKEN: ${{ secrets.PAT_TOKEN }} - run: | - if [ -z "$PAT_TOKEN" ]; then - echo "::warning::PAT_TOKEN secret is not configured." - echo "::warning::If this sync modifies workflow files, the push will fail." - echo "::warning::See .rhiza/docs/TOKEN_SETUP.md for setup instructions." - else - echo "✓ PAT_TOKEN is configured." - fi - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - - - name: Get Rhiza version - id: rhiza-version - run: | - VERSION=$(cat .rhiza/.rhiza-version 2>/dev/null || echo "0.9.0") - echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - - - name: Sync rhiza template - id: sync - run: | - set -euo pipefail - - RHIZA_VERSION="${{ steps.rhiza-version.outputs.version }}" - - echo "Running rhiza sync with version >=${RHIZA_VERSION}" - uvx "rhiza>=${RHIZA_VERSION}" sync . - - if git diff --quiet; then - echo "No changes detected after template sync" - echo "changes=false" >> "$GITHUB_OUTPUT" - exit 0 - fi - - echo "Template changes detected" - echo "changes=true" >> "$GITHUB_OUTPUT" - - - name: Commit and push changes - if: steps.sync.outputs.changes == 'true' - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --global url."https://x-access-token:${{ secrets.PAT_TOKEN || github.token }}@github.com/".insteadOf "https://github.com/" - - git add -A - git commit -m "$(cat <<'EOF' - chore: sync rhiza template files - - Automatically synced template files after updating .rhiza/template.yml - - Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> - EOF - )" - - git push diff --git a/.github/workflows/rhiza_book.yml b/.github/workflows/rhiza_book.yml index dba3a9c..778c6f4 100644 --- a/.github/workflows/rhiza_book.yml +++ b/.github/workflows/rhiza_book.yml @@ -43,7 +43,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7.6.0 with: - version: "0.10.12" + version: "0.11.2" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth @@ -88,5 +88,5 @@ jobs: # If PUBLISH_COMPANION_BOOK is not set, it defaults to allowing deployment - name: Deploy to GitHub Pages if: ${{ !github.event.repository.fork && (vars.PUBLISH_COMPANION_BOOK == 'true' || vars.PUBLISH_COMPANION_BOOK == '') }} - uses: actions/deploy-pages@v4.0.5 # Official GitHub Pages deployment action + uses: actions/deploy-pages@v5.0.0 # Official GitHub Pages deployment action continue-on-error: true diff --git a/.github/workflows/rhiza_ci.yml b/.github/workflows/rhiza_ci.yml index f80b693..d478e15 100644 --- a/.github/workflows/rhiza_ci.yml +++ b/.github/workflows/rhiza_ci.yml @@ -3,9 +3,11 @@ # # Workflow: Continuous Integration # -# Purpose: Run tests on multiple Python versions to ensure compatibility. +# Purpose: Run tests on multiple Python versions, check dependencies, run +# pre-commit hooks, verify documentation coverage, validate the +# project, run security scans, and check license compliance. # -# Trigger: On push and pull requests to main/master branches. +# Trigger: On push and pull_request. name: (RHIZA) CI @@ -15,9 +17,7 @@ permissions: on: push: - branches: [ main, master ] pull_request: - branches: [ main, master ] jobs: generate-matrix: @@ -32,13 +32,13 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7.6.0 with: - version: "0.10.12" + version: "0.11.2" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth with: token: ${{ secrets.GH_PAT }} - + - id: versions env: UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} @@ -53,10 +53,11 @@ jobs: test: needs: generate-matrix - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: matrix: python-version: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} + os: [ubuntu-latest, macos-latest, windows-latest] fail-fast: false steps: @@ -68,7 +69,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7.6.0 with: - version: "0.10.12" + version: "0.11.2" python-version: ${{ matrix.python-version }} - name: Configure git auth for private packages @@ -83,7 +84,7 @@ jobs: make test - name: Upload coverage report - if: matrix.python-version == '3.12' + if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest' uses: actions/upload-artifact@v7 with: name: coverage-report @@ -91,6 +92,74 @@ jobs: if-no-files-found: ignore + typecheck: + name: Type checking + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + with: + version: "0.11.2" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run ty type checker (make typecheck) + # Runs `uv run ty check src/` as defined in .rhiza/make.d/test.mk. + # ty is configured via [tool.ty.environment] in pyproject.toml. + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make typecheck + + deptry: + name: Check dependencies with deptry + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + with: + version: "0.11.2" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run deptry + run: make deptry + + pre-commit: + name: Pre-commit hooks + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Cache pre-commit environments + uses: actions/cache@v5 + with: + path: ~/.cache/pre-commit + key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }} + restore-keys: | + pre-commit-${{ runner.os }}- + + - name: Run pre-commit + run: | + make fmt + docs-coverage: runs-on: ubuntu-latest steps: @@ -100,7 +169,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7.6.0 with: - version: "0.10.12" + version: "0.11.2" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth @@ -113,6 +182,87 @@ jobs: run: | make docs-coverage + validation: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.2 + with: + lfs: true + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + with: + version: "0.11.2" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Validate + shell: bash + run: | + make validate + + security: + name: Security scanning + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + with: + version: "0.11.2" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run security scans + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make security + + license: + name: License compliance scan + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + with: + version: "0.11.2" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run license check + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make license + + - name: Generate LICENSES.md + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: | + uv run --with pip-licenses pip-licenses --format markdown --output-file LICENSES.md + + - name: Upload LICENSES.md + uses: actions/upload-artifact@v7 + with: + name: LICENSES.md + path: LICENSES.md + if-no-files-found: ignore + coverage-badge: needs: test runs-on: ubuntu-latest @@ -128,7 +278,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7.6.0 with: - version: "0.10.12" + version: "0.11.2" - name: Download coverage report id: download-coverage diff --git a/.github/workflows/rhiza_dep_compat_test.yml b/.github/workflows/rhiza_dep_compat_test.yml deleted file mode 100644 index b2acb40..0000000 --- a/.github/workflows/rhiza_dep_compat_test.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: "(RHIZA) DEPENDENCY COMPATIBILITY (WEEKLY)" - -# Resolves all dependencies fresh—ignoring the committed lockfile—and runs -# the full test suite. Failure here means a newly-released package version -# (e.g. pydantic v3, scipy v2, numpy v3) is incompatible with the current -# code, providing an early-warning signal before the lockfile is next -# refreshed by Renovate or a manual bump. -# -# See: https://github.com/Jebel-Quant/basanos/issues/ - -permissions: - contents: read - -on: - schedule: - - cron: "0 9 * * 3" # Every Wednesday at 09:00 UTC - workflow_dispatch: - -jobs: - dep-compat-test: - name: Test with latest compatible dependencies - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - lfs: true - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Resolve and install latest compatible dependencies - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: | - # --upgrade ignores the committed lockfile and resolves the newest - # versions that satisfy pyproject.toml constraints. - uv sync --upgrade - - - name: Show resolved package versions - run: | - echo "=== Installed package versions ===" - uv pip list - - - name: Run tests - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make test diff --git a/.github/workflows/rhiza_deptry.yml b/.github/workflows/rhiza_deptry.yml deleted file mode 100644 index 42fe31b..0000000 --- a/.github/workflows/rhiza_deptry.yml +++ /dev/null @@ -1,48 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Deptry -# -# Purpose: This workflow identifies missing and obsolete dependencies in the project. -# It helps maintain a clean dependency tree by detecting unused packages and -# implicit dependencies that should be explicitly declared. -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) - -name: "(RHIZA) DEPTRY" - -# Permissions: Only read access to repository contents is needed -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - deptry: - name: Check dependencies with deptry - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run deptry - run: make deptry - # NOTE: make deptry is good style because it encapsulates the folders to check - # (e.g. src and book/marimo) and keeps CI in sync with local development. - # Since we have uv/uvx installed, the Makefile is optimised to use the - # pre-installed 'uv' and 'uvx' from the system PATH. diff --git a/.github/workflows/rhiza_license.yml b/.github/workflows/rhiza_license.yml deleted file mode 100644 index e6647c9..0000000 --- a/.github/workflows/rhiza_license.yml +++ /dev/null @@ -1,45 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: License compliance -# -# Purpose: This workflow checks that no copyleft-licensed dependencies -# (GPL, LGPL, AGPL) have been introduced via transitive updates. -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) - -name: "(RHIZA) LICENSE" - -# Permissions: Only read access to repository contents is needed -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - license: - name: License compliance scan - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run license check - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make license diff --git a/.github/workflows/rhiza_pip_audit.yml b/.github/workflows/rhiza_pip_audit.yml deleted file mode 100644 index e6719a9..0000000 --- a/.github/workflows/rhiza_pip_audit.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: "(RHIZA) PIP-AUDIT (WEEKLY)" - -permissions: - contents: read - -on: - schedule: - - cron: "0 9 * * 1" # Every Monday at 09:00 UTC (GitHub Actions: 0=Sunday, 1=Monday) - workflow_dispatch: - -jobs: - pip-audit: - name: Dependency vulnerability scan - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" - - - name: Run pip-audit - run: uvx pip-audit diff --git a/.github/workflows/rhiza_pre-commit.yml b/.github/workflows/rhiza_pre-commit.yml deleted file mode 100644 index df38fa0..0000000 --- a/.github/workflows/rhiza_pre-commit.yml +++ /dev/null @@ -1,52 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Pre-commit -# -# Purpose: This workflow runs pre-commit checks to ensure code quality -# and consistency across the codebase. It helps catch issues -# like formatting errors, linting issues, and other code quality -# problems before they are merged. -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) -# -# Components: -# - 🔍 Run pre-commit checks using reusable action -# - 💾 Cache pre-commit environments to speed up runs - -name: "(RHIZA) PRE-COMMIT" -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - pre-commit: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - # Cache pre-commit environments and hooks - - name: Cache pre-commit environments - uses: actions/cache@v5 - with: - path: ~/.cache/pre-commit - key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }} - restore-keys: | - pre-commit-${{ runner.os }}- - - # Run pre-commit - - name: Run pre-commit - run: | - make fmt diff --git a/.github/workflows/rhiza_release.yml b/.github/workflows/rhiza_release.yml index 24b9359..9003813 100644 --- a/.github/workflows/rhiza_release.yml +++ b/.github/workflows/rhiza_release.yml @@ -122,7 +122,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7.6.0 with: - version: "0.10.12" + version: "0.11.2" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth @@ -223,6 +223,17 @@ jobs: needs: [tag, build] steps: + - name: Checkout Code + uses: actions/checkout@v6.0.2 + with: + fetch-depth: 0 + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + + - name: Generate release notes with git-cliff + run: uvx git-cliff --latest --output RELEASE_NOTES.md + - name: Download SBOM artifact # Downloads sbom.cdx.json and sbom.cdx.xml into sbom/ directory uses: actions/download-artifact@v8.0.1 @@ -236,10 +247,9 @@ jobs: with: tag: ${{ needs.tag.outputs.tag }} name: ${{ needs.tag.outputs.tag }} - generateReleaseNotes: true + bodyFile: RELEASE_NOTES.md draft: true allowUpdates: true - omitBodyDuringUpdate: true artifacts: "sbom/*" # Decide at step-level whether to publish @@ -393,7 +403,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7.6.0 with: - version: "0.10.12" + version: "0.11.2" - name: "Sync the virtual environment for ${{ github.repository }}" shell: bash diff --git a/.github/workflows/rhiza_security.yml b/.github/workflows/rhiza_security.yml deleted file mode 100644 index 9d95d61..0000000 --- a/.github/workflows/rhiza_security.yml +++ /dev/null @@ -1,46 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Security -# -# Purpose: This workflow runs security scans on the project including: -# - pip-audit: Check for known vulnerabilities in dependencies -# - bandit: Static analysis for common security issues in Python code -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) - -name: "(RHIZA) SECURITY" - -# Permissions: Only read access to repository contents is needed -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - security: - name: Security scanning - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run security scans - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make security diff --git a/.github/workflows/rhiza_semgrep.yml b/.github/workflows/rhiza_semgrep.yml deleted file mode 100644 index 51e447b..0000000 --- a/.github/workflows/rhiza_semgrep.yml +++ /dev/null @@ -1,48 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Semgrep -# -# Purpose: This workflow runs static analysis using Semgrep with local numpy -# rules (.semgrep.yml) to detect common NumPy-related bugs and -# security issues in Python code. -# Note: the retired p/numpy registry ruleset is replaced by a local -# rules file that covers the same concerns. -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) - -name: "(RHIZA) SEMGREP" - -# Permissions: Only read access to repository contents is needed -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - semgrep: - name: Semgrep (numpy) - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run Semgrep - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make semgrep diff --git a/.github/workflows/rhiza_sync.yml b/.github/workflows/rhiza_sync.yml index 9d06fd2..7df732b 100644 --- a/.github/workflows/rhiza_sync.yml +++ b/.github/workflows/rhiza_sync.yml @@ -1,27 +1,107 @@ name: (RHIZA) SYNC -# This workflow synchronizes the repository with its template. -# IMPORTANT: When workflow files (.github/workflows/rhiza_*.yml) are modified, -# a Personal Access Token (PAT) with 'workflow' scope is required. -# The PAT_TOKEN secret must be set in repository secrets. -# See .github/rhiza/TOKEN_SETUP.md for setup instructions. +# Synchronizes the repository with its rhiza template. +# - On Renovate/rhiza branch push: auto-commits synced files directly to the branch. +# - On schedule/dispatch: opens a pull request with the synced changes. +# +# IMPORTANT: A PAT with 'workflow' scope (PAT_TOKEN) is required when workflow +# files are modified. See .rhiza/docs/TOKEN_SETUP.md for setup instructions. permissions: contents: write pull-requests: write on: + push: + branches: + - 'renovate/jebel-quant-rhiza-**' + - 'rhiza/**' + paths: + - '.rhiza/template.yml' + schedule: + - cron: '0 0 * * 1' # Weekly on Monday workflow_dispatch: inputs: create-pr: description: "Create a pull request" type: boolean default: true - schedule: - - cron: '0 0 * * 1' # Weekly on Monday jobs: - sync: - if: ${{ github.repository != 'jebel-quant/rhiza' }} + sync-direct: + name: Sync and commit (Renovate) + if: github.event_name == 'push' && github.repository != 'jebel-quant/rhiza' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.2 + with: + ref: ${{ github.ref }} + token: ${{ secrets.PAT_TOKEN || github.token }} + + - name: Check PAT_TOKEN configuration + shell: bash + env: + PAT_TOKEN: ${{ secrets.PAT_TOKEN }} + run: | + if [ -z "$PAT_TOKEN" ]; then + echo "::warning::PAT_TOKEN secret is not configured." + echo "::warning::If this sync modifies workflow files, the push will fail." + echo "::warning::See .rhiza/docs/TOKEN_SETUP.md for setup instructions." + else + echo "✓ PAT_TOKEN is configured." + fi + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + + - name: Get Rhiza version + id: rhiza-version + run: | + VERSION=$(cat .rhiza/.rhiza-version 2>/dev/null || echo "0.9.0") + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + + - name: Sync rhiza template + id: sync + run: | + set -euo pipefail + + RHIZA_VERSION="${{ steps.rhiza-version.outputs.version }}" + + echo "Running rhiza sync with version >=${RHIZA_VERSION}" + uvx "rhiza>=${RHIZA_VERSION}" sync . + + if git diff --quiet; then + echo "No changes detected after template sync" + echo "changes=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + echo "Template changes detected" + echo "changes=true" >> "$GITHUB_OUTPUT" + + - name: Commit and push changes + if: steps.sync.outputs.changes == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global url."https://x-access-token:${{ secrets.PAT_TOKEN || github.token }}@github.com/".insteadOf "https://github.com/" + + git add -A + git commit -m "$(cat <<'EOF' + chore: sync rhiza template files + + Automatically synced template files after updating .rhiza/template.yml + + Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> + EOF + )" + + git push + + sync-pr: + name: Sync and open PR (scheduled/manual) + if: github.event_name != 'push' && github.repository != 'jebel-quant/rhiza' runs-on: ubuntu-latest steps: @@ -44,7 +124,7 @@ jobs: if [ -z "$PAT_TOKEN" ]; then echo "::warning::PAT_TOKEN secret is not configured." echo "::warning::If this sync modifies workflow files, the push will fail." - echo "::warning::See .github/TOKEN_SETUP.md for setup instructions." + echo "::warning::See .rhiza/docs/TOKEN_SETUP.md for setup instructions." else echo "✓ PAT_TOKEN is configured." fi @@ -85,7 +165,7 @@ jobs: git config --global url."https://x-access-token:${{ secrets.PAT_TOKEN }}@github.com/".insteadOf "https://github.com/" git commit -m "chore: Update via rhiza" - + - name: Create pull request if: > (github.event_name == 'schedule' || inputs.create-pr == true) @@ -97,4 +177,4 @@ jobs: branch: ${{ steps.branch.outputs.name }} delete-branch: true title: "chore: Sync with rhiza" - body-path: ${{ runner.temp }}/pr-description.md \ No newline at end of file + body-path: ${{ runner.temp }}/pr-description.md diff --git a/.github/workflows/rhiza_typecheck.yml b/.github/workflows/rhiza_typecheck.yml deleted file mode 100644 index 7d87f0b..0000000 --- a/.github/workflows/rhiza_typecheck.yml +++ /dev/null @@ -1,50 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Type Checking -# -# Purpose: Run static type analysis using ty to enforce type safety. -# ty (https://github.com/astral-sh/ty) is a fast Python type checker -# from the Astral team (same team as ruff/uv). -# -# Type-checker settings live in [tool.ty.environment] in pyproject.toml. -# Locally, `make typecheck` runs the same check; it is also wired into -# `make validate` via the `post-validate::` hook in the repo Makefile. -# -# Trigger: On push and pull requests to main/master branches. - -name: "(RHIZA) TYPECHECK" - -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - typecheck: - name: Type checking - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run ty type checker (make typecheck) - # Runs `uv run ty check src/` as defined in .rhiza/make.d/test.mk. - # ty is configured via [tool.ty.environment] in pyproject.toml. - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make typecheck diff --git a/.github/workflows/rhiza_validate.yml b/.github/workflows/rhiza_validate.yml deleted file mode 100644 index 04813a6..0000000 --- a/.github/workflows/rhiza_validate.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: (RHIZA) VALIDATE - -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - validation: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - lfs: true - - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Validate - shell: bash - run: | - make validate diff --git a/.github/workflows/rhiza_weekly.yml b/.github/workflows/rhiza_weekly.yml new file mode 100644 index 0000000..f4b5683 --- /dev/null +++ b/.github/workflows/rhiza_weekly.yml @@ -0,0 +1,118 @@ +name: "(RHIZA) WEEKLY" + +# Runs weekly checks that are too slow or noisy for every push: +# +# dep-compat-test — Resolves all dependencies fresh (ignoring the lockfile) +# and runs the full test suite. Catches newly-released +# packages that break compatibility before Renovate picks +# them up. Runs on schedule/dispatch only. +# +# link-check — Verifies that all hyperlinks in README.md are reachable. +# Runs on schedule/dispatch only. + +permissions: + contents: read + +on: + #push: + # branches: [main] + # paths: [README.md] + #pull_request: + # paths: [README.md] + schedule: + - cron: "0 8 * * 1" # Every Monday at 08:00 UTC + workflow_dispatch: + +jobs: + dep-compat-test: + name: Test with latest compatible dependencies + runs-on: ubuntu-latest + #if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.2 + with: + lfs: true + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + with: + version: "0.11.2" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Resolve and install latest compatible dependencies + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: | + # --upgrade ignores the committed lockfile and resolves the newest + # versions that satisfy pyproject.toml constraints. + uv sync --upgrade + + - name: Show resolved package versions + run: | + echo "=== Installed package versions ===" + uv pip list + + - name: Run tests + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make test + + semgrep: + name: Semgrep (numpy) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + with: + version: "0.11.2" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run Semgrep + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make semgrep + + pip-audit: + name: Dependency vulnerability scan + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v7.6.0 + with: + version: "0.11.2" + + - name: Run pip-audit + run: uvx pip-audit + + link-check: + name: Check links in README.md + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Check links in README.md + uses: lycheeverse/lychee-action@v2 + with: + args: >- + --verbose + --no-progress + --accept 200,206,429 + README.md + fail: true diff --git a/.gitignore b/.gitignore index 0d16b94..24c7706 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,14 @@ _benchmarks _jupyter _site +# LaTeX build artifacts +docs/paper/*.aux +docs/paper/*.fdb_latexmk +docs/paper/*.fls +docs/paper/*.log +docs/paper/*.out +docs/paper/*.toc + # temp file used by Junie .output.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 298f634..4664a34 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,9 +8,10 @@ repos: - id: check-toml - id: check-yaml args: ['--unsafe'] + exclude: ^recipe/meta\.yaml$ - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 'v0.15.7' + rev: 'v0.15.8' hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix, --unsafe-fixes ] @@ -25,7 +26,7 @@ repos: args: ["--disable", "MD013"] - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.37.0 + rev: 0.37.1 hooks: - id: check-renovate args: [ "--verbose" ] @@ -50,12 +51,12 @@ repos: args: ["--skip", "B101", "--exclude", ".venv,tests,.rhiza/tests,.git,.pytest_cache", "-c", "pyproject.toml"] - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.10.12 + rev: 0.11.2 hooks: - id: uv-lock - repo: https://github.com/Jebel-Quant/rhiza-hooks - rev: v0.3.0 # Use the latest release + rev: v0.3.1 # Use the latest release hooks: # Migrated from rhiza - id: check-rhiza-workflow-names diff --git a/.rhiza/make.d/quality.mk b/.rhiza/make.d/quality.mk index 1efd063..32007f3 100644 --- a/.rhiza/make.d/quality.mk +++ b/.rhiza/make.d/quality.mk @@ -1,11 +1,14 @@ ## .rhiza/make.d/quality.mk - Quality and Formatting # This file provides targets for code quality checks, linting, and formatting. +# Configurable list of licenses that fail the compliance scan (semicolon-separated) +LICENSE_FAIL_ON ?= GPL;LGPL;AGPL + # Declare phony targets (they don't produce files) -.PHONY: all deptry fmt todos +.PHONY: all deptry fmt license todos suppression-audit ##@ Quality and Formatting -all: fmt deptry test docs-coverage security typecheck rhiza-test ## run all CI targets locally +all: fmt deptry test docs-coverage security license typecheck rhiza-test ## run all CI targets locally deptry: install-uv ## Run deptry @if [ -d ${SOURCE_FOLDER} ]; then \ @@ -38,3 +41,11 @@ todos: ## search and report all TODO/FIXME/HACK comments in the codebase awk -F: '{ printf "${YELLOW}%s${RESET}:${GREEN}%s${RESET}: %s\n", $$1, $$2, substr($$0, index($$0,$$3)) }' || \ printf "${GREEN}[SUCCESS] No TODO/FIXME/HACK comments found!${RESET}\n" @printf "\n${BLUE}[INFO] Search complete.${RESET}\n" + +suppression-audit: ## scan codebase for inline suppressions and report (grade, detail, histogram) + @printf "${BLUE}[INFO] Running suppression audit...${RESET}\n" + @${UV_BIN} run python .rhiza/utils/suppression_audit.py + +license: install ## run license compliance scan (fail on GPL, LGPL, AGPL) + @printf "${BLUE}[INFO] Running license compliance scan...${RESET}\n" + @${UV_BIN} run --with pip-licenses pip-licenses --fail-on="${LICENSE_FAIL_ON}" diff --git a/.semgrep.yml b/.rhiza/semgrep.yml similarity index 100% rename from .semgrep.yml rename to .rhiza/semgrep.yml diff --git a/.rhiza/template.lock b/.rhiza/template.lock index 9d0168c..d86b02d 100644 --- a/.rhiza/template.lock +++ b/.rhiza/template.lock @@ -1,7 +1,7 @@ -sha: bbe56565ed221032435bff43b00598e3efa046ef +sha: 8fa3c9b166c1c21f1a2752c77913f55c66213dce repo: jebel-quant/rhiza host: github -ref: v0.8.16 +ref: v0.8.20 include: [] exclude: [] templates: @@ -9,6 +9,7 @@ templates: - tests - legal - book +- renovate files: - .editorconfig - .github/DISCUSSION_TEMPLATE/q-and-a.yml @@ -25,21 +26,12 @@ files: - .github/hooks/session-start.sh - .github/secret_scanning.yml - .github/workflows/copilot-setup-steps.yml -- .github/workflows/renovate_rhiza_sync.yml - .github/workflows/rhiza_book.yml - .github/workflows/rhiza_ci.yml - .github/workflows/rhiza_codeql.yml -- .github/workflows/rhiza_dep_compat_test.yml -- .github/workflows/rhiza_deptry.yml -- .github/workflows/rhiza_license.yml -- .github/workflows/rhiza_pip_audit.yml -- .github/workflows/rhiza_pre-commit.yml - .github/workflows/rhiza_release.yml -- .github/workflows/rhiza_security.yml -- .github/workflows/rhiza_semgrep.yml - .github/workflows/rhiza_sync.yml -- .github/workflows/rhiza_typecheck.yml -- .github/workflows/rhiza_validate.yml +- .github/workflows/rhiza_weekly.yml - .gitignore - .pre-commit-config.yaml - .python-version @@ -72,6 +64,7 @@ files: - .rhiza/requirements/tests.txt - .rhiza/requirements/tools.txt - .rhiza/rhiza.mk +- .rhiza/semgrep.yml - .rhiza/templates/minibook/custom.html.jinja2 - .rhiza/tests/README.md - .rhiza/tests/api/conftest.py @@ -83,7 +76,6 @@ files: - .rhiza/tests/deps/test_dependency_health.py - .rhiza/tests/integration/test_book_targets.py - .rhiza/tests/integration/test_lfs.py -- .rhiza/tests/integration/test_marimushka.py - .rhiza/tests/integration/test_sbom.py - .rhiza/tests/integration/test_test_mk.py - .rhiza/tests/integration/test_virtual_env_unexport.py @@ -104,7 +96,6 @@ files: - .rhiza/tests/sync/test_rhiza_version.py - .rhiza/tests/test_utils.py - .rhiza/tests/utils/test_git_repo_fixture.py -- .semgrep.yml - CODE_OF_CONDUCT.md - CONTRIBUTING.md - LICENSE @@ -119,6 +110,7 @@ files: - docs/SECURITY.md - docs/TESTS.md - pytest.ini +- renovate.json - ruff.toml -synced_at: '2026-03-22T11:32:55Z' +synced_at: '2026-04-02T06:27:26Z' strategy: merge diff --git a/.rhiza/tests/api/test_makefile_targets.py b/.rhiza/tests/api/test_makefile_targets.py index 7a90200..1ea7747 100644 --- a/.rhiza/tests/api/test_makefile_targets.py +++ b/.rhiza/tests/api/test_makefile_targets.py @@ -189,6 +189,27 @@ def test_coverage_badge_skips_without_source_folder(self, logger, tmp_path): assert "nonexistent_src" in out assert "skipping coverage-badge" in out + def test_suppression_audit_target_dry_run(self, logger): + """Suppression-audit target should invoke the Python audit script via uv run in dry-run output.""" + proc = run_make(logger, ["suppression-audit"]) + out = proc.stdout + assert "uv run python" in out + assert "suppression_audit.py" in out + + def test_license_target_dry_run(self, logger): + """License target should invoke pip-licenses via uv run --with in dry-run output.""" + proc = run_make(logger, ["license"]) + out = proc.stdout + assert "uv run --with pip-licenses pip-licenses" in out + assert "--fail-on=" in out + assert "GPL" in out + + def test_license_fail_on_is_configurable(self, logger): + """License target should use the LICENSE_FAIL_ON variable for the fail-on list.""" + proc = run_make(logger, ["license", "LICENSE_FAIL_ON=MIT;Apache"]) + out = proc.stdout + assert '--fail-on="MIT;Apache"' in out + class TestMakefileRootFixture: """Tests for root fixture usage in Makefile tests.""" diff --git a/.rhiza/tests/integration/test_marimushka.py b/.rhiza/tests/integration/test_marimushka.py deleted file mode 100644 index 6abdaa9..0000000 --- a/.rhiza/tests/integration/test_marimushka.py +++ /dev/null @@ -1,93 +0,0 @@ -"""Tests for the marimushka Makefile target using a sandboxed environment. - -This file and its associated tests flow down via a SYNC action from the jebel-quant/rhiza repository -(https://github.com/jebel-quant/rhiza). - -Provides test fixtures for testing git-based workflows and version management. -""" - -import os -import shutil -import subprocess # nosec - -import pytest - -# Get shell path and make command once at module level -SHELL = shutil.which("sh") or "/bin/sh" -MAKE = shutil.which("make") or "/usr/bin/make" - - -def test_marimushka_target_success(git_repo): - """Test successful execution of the marimushka Makefile target.""" - # only run this test if the marimo folder is present - if not (git_repo / "book" / "marimo").exists(): - pytest.skip("marimo folder not found, skipping test") - - # Setup directories in the git repo - marimo_folder = git_repo / "book" / "marimo" / "notebooks" - marimo_folder.mkdir(parents=True, exist_ok=True) - (marimo_folder / "notebook.py").touch() - - output_folder = git_repo / "_marimushka" - - # Run the make target - env = os.environ.copy() - env["MARIMO_FOLDER"] = "book/marimo/notebooks" - env["MARIMUSHKA_OUTPUT"] = "_marimushka" - - # Create dummy bin/uv and bin/uvx if they don't exist - (git_repo / "bin").mkdir(exist_ok=True) - (git_repo / "bin" / "uv").touch() - (git_repo / "bin" / "uv").chmod(0o755) - (git_repo / "bin" / "uvx").touch() - (git_repo / "bin" / "uvx").chmod(0o755) - - # Put our bin on the PATH so 'command -v uvx' finds it in the test - env["PATH"] = f"{git_repo}/bin:{env.get('PATH', '')}" - - # In tests, we don't want to actually run marimushka as it's not installed in the mock env - # But we want to test that the Makefile logic works. - # We can mock the marimushka CLI call by creating a script that generates the expected files. - with open(git_repo / "bin" / "marimushka", "w") as f: - f.write( - f"#!/bin/sh\nmkdir -p {output_folder}/notebooks\n" - f"touch {output_folder}/index.html\n" - f"touch {output_folder}/notebooks/notebook.html\n" - ) - (git_repo / "bin" / "marimushka").chmod(0o755) - - # Override UVX_BIN to use our mock marimushka CLI - env["UVX_BIN"] = str(git_repo / "bin" / "marimushka") - - result = subprocess.run([MAKE, "marimushka"], env=env, cwd=git_repo, capture_output=True, text=True) # nosec - - assert result.returncode == 0 - assert "Exporting notebooks" in result.stdout - assert (output_folder / "index.html").exists() - assert (output_folder / "notebooks" / "notebook.html").exists() - - -def test_marimushka_no_python_files(git_repo): - """Test marimushka target behavior when MARIMO_FOLDER has no python files.""" - if not (git_repo / "book" / "marimo").exists(): - pytest.skip("marimo folder not found, skipping test") - - marimo_folder = git_repo / "book" / "marimo" / "notebooks" - marimo_folder.mkdir(parents=True, exist_ok=True) - - # Delete all .py files in the marimo folder - for file in marimo_folder.glob("*.py"): - file.unlink() - - # No .py files created - - output_folder = git_repo / "_marimushka" - - env = os.environ.copy() - env["MARIMO_FOLDER"] = "book/marimo/notebooks" - env["MARIMUSHKA_OUTPUT"] = "_marimushka" - - result = subprocess.run([MAKE, "marimushka"], env=env, cwd=git_repo, capture_output=True, text=True) # nosec - - assert result.returncode == 0 - assert (output_folder / "index.html").exists() diff --git a/Makefile b/Makefile index 6da15f2..1044038 100644 --- a/Makefile +++ b/Makefile @@ -18,22 +18,27 @@ post-validate:: ## Custom targets +##@ Security + + +#.PHONY: security +#security: install ## run security scans (pip-audit and bandit) +# @printf "${BLUE}[INFO] Running pip-audit for dependency vulnerabilities...${RESET}\n" +# @${UVX_BIN} pip-audit +# @printf "${BLUE}[INFO] Running bandit security scan...${RESET}\n" +# @${UVX_BIN} bandit -r ${SOURCE_FOLDER} -ll -q -c pyproject.toml + ##@ Quality .PHONY: semgrep semgrep: install ## run Semgrep static analysis (numpy rules) @printf "${BLUE}[INFO] Running Semgrep (numpy rules)...${RESET}\n" @if [ -d ${SOURCE_FOLDER} ]; then \ - ${UVX_BIN} semgrep --config .semgrep.yml ${SOURCE_FOLDER}; \ + ${UVX_BIN} semgrep --config .rhiza/semgrep.yml ${SOURCE_FOLDER}; \ else \ printf "${YELLOW}[WARN] SOURCE_FOLDER '${SOURCE_FOLDER}' not found, skipping semgrep.${RESET}\n"; \ fi -.PHONY: license -license: install ## run license compliance scan (fail on GPL, LGPL, AGPL) - @printf "${BLUE}[INFO] Running license compliance scan...${RESET}\n" - @${UV_BIN} run --with pip-licenses pip-licenses --fail-on="GPL;LGPL;AGPL" - .PHONY: adr adr: install-gh-aw ## Create a new Architecture Decision Record (ADR) using AI assistance @echo "Creating a new ADR..." diff --git a/docs/CUSTOMIZATION.md b/docs/CUSTOMIZATION.md index a446e29..7437856 100644 --- a/docs/CUSTOMIZATION.md +++ b/docs/CUSTOMIZATION.md @@ -157,7 +157,7 @@ For example, to override the main module template, create `book/pdoc-templates/m See the [pdoc documentation on templates](https://pdoc.dev/docs/pdoc.html#edit-pdocs-html-template) for full details on how to override specific parts of the documentation. -For more details on customizing the documentation, see [book/README.md](../book/README.md). +For more details on customizing the documentation, see [book/README.md](BOOK.md). ## 📖 Complete Documentation diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..1be6982 --- /dev/null +++ b/renovate.json @@ -0,0 +1,57 @@ +{ + "extends": [ + "config:recommended", + ":enablePreCommit", + ":automergeMinor", + ":dependencyDashboard", + ":maintainLockFilesWeekly", + ":semanticCommits", + ":pinDevDependencies" + ], + "rebaseWhen": "behind-base-branch", + "enabledManagers": [ + "pep621", + "pre-commit", + "github-actions", + "gitlabci", + "devcontainer", + "dockerfile", + "custom.regex" + ], + "timezone": "Asia/Dubai", + "schedule": [ + "before 3am" + ], + "packageRules": [ + { + "matchManagers": [ + "pep621" + ], + "matchPackageNames": [ + "python" + ], + "enabled": false + }, + { + "matchManagers": [ + "custom.regex" + ], + "matchPackageNames": [ + "jebel-quant/rhiza" + ], + "automerge": false + } + ], + "customManagers": [ + { + "customType": "regex", + "managerFilePatterns": [ + "/(^|/)\\.rhiza/template\\.yml$/" + ], + "matchStrings": [ + "(?:repository|template-repository):\\s*\"(?[^\"]+)\"[\\s\\S]*?(?:ref|template-branch):\\s*\"(?[^\"]+)\"" + ], + "datasourceTemplate": "github-releases" + } + ] +} From 8d703b4728cdc688b1ce25e86a3a7dd8dd935ff4 Mon Sep 17 00:00:00 2001 From: Thomas Schmelzer Date: Thu, 2 Apr 2026 10:34:31 +0400 Subject: [PATCH 3/4] Fix UnicodeEncodeError on Windows for checkmark characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reconfigure stdout to UTF-8 at the start of main() so that ✓ and ✗ can be printed on Windows systems where the default encoding is cp1252. Co-Authored-By: Claude Sonnet 4.6 --- src/rhiza_hooks/check_template_bundles.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rhiza_hooks/check_template_bundles.py b/src/rhiza_hooks/check_template_bundles.py index 7a8ae17..88153d6 100644 --- a/src/rhiza_hooks/check_template_bundles.py +++ b/src/rhiza_hooks/check_template_bundles.py @@ -384,6 +384,8 @@ def _validate_templates_in_bundles(templates_set: set[str], bundles: dict[Any, A def main(argv: list[str] | None = None) -> int: """Main entry point.""" + if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") parser = argparse.ArgumentParser(description="Validate template-bundles.yml from remote template repository") parser.add_argument( "filenames", From d064dafd804e34ed46ab97af031552f3cf1512f0 Mon Sep 17 00:00:00 2001 From: Thomas Schmelzer Date: Thu, 2 Apr 2026 10:37:53 +0400 Subject: [PATCH 4/4] Fix typecheck: use isinstance check for stdout.reconfigure Replace hasattr with isinstance(sys.stdout, io.TextIOWrapper) so ty can resolve the reconfigure method type correctly. Co-Authored-By: Claude Sonnet 4.6 --- src/rhiza_hooks/check_template_bundles.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rhiza_hooks/check_template_bundles.py b/src/rhiza_hooks/check_template_bundles.py index 88153d6..aeb5eb3 100644 --- a/src/rhiza_hooks/check_template_bundles.py +++ b/src/rhiza_hooks/check_template_bundles.py @@ -19,6 +19,7 @@ from __future__ import annotations import argparse +import io import sys from pathlib import Path from typing import Any, cast @@ -384,7 +385,7 @@ def _validate_templates_in_bundles(templates_set: set[str], bundles: dict[Any, A def main(argv: list[str] | None = None) -> int: """Main entry point.""" - if hasattr(sys.stdout, "reconfigure"): + if isinstance(sys.stdout, io.TextIOWrapper): sys.stdout.reconfigure(encoding="utf-8", errors="replace") parser = argparse.ArgumentParser(description="Validate template-bundles.yml from remote template repository") parser.add_argument(