fix: disable debug=True / Werkzeug debugger exposure (closes #9) (#20) #6
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: Tests | |
| on: | |
| push: | |
| branches: [master] | |
| pull_request: | |
| # Least-privilege GITHUB_TOKEN scope. None of these jobs need write access | |
| # (no commit, no PR comment, no release publish) — read-only is enough. | |
| # A compromised action in any matrix cell can't write back to the repo. | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # ── Unit tests: matrix across OS and Python version ─────────────────────── | |
| # Closes #13. The unittest suite is the merge gate. Multi-OS catches the | |
| # rare path / line-ending issue that a single-OS run hides; multi-Python | |
| # catches API drift across LTS / current / latest interpreters. | |
| unittest: | |
| name: Unit tests (${{ matrix.os }} / Python ${{ matrix.python-version }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest] | |
| python-version: ["3.11", "3.12", "3.13"] | |
| steps: | |
| # Pinned to immutable commit SHAs (not @v4 / @v5) so a compromised tag | |
| # cannot silently swap the underlying action code on this CI runner. | |
| # When bumping, verify the new SHA via: | |
| # gh api repos/actions/<name>/git/ref/tags/<vN> --jq '.object.sha' | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install runtime + test dependencies | |
| # Only what the tests actually exercise. `pywebview` from | |
| # requirements.txt is the desktop-launcher dep and pulls GTK / Qt | |
| # system packages on Linux — out of scope for the unittest suite. | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install 'flask>=3.0' 'fpdf2>=2.7' | |
| - name: Run unittest suite | |
| run: python -m unittest discover tests -v | |
| # ── Typecheck: mypy ─────────────────────────────────────────────────────── | |
| # Codebase already has type hints across most of the surface (~70+ typed | |
| # functions). Mypy runs in lenient mode (--ignore-missing-imports for | |
| # untyped third-party deps; no strict-optional) so the gate isn't a wall | |
| # of false positives on first run. continue-on-error keeps findings as | |
| # warnings during the surface-cleanup phase; flip to required by removing | |
| # continue-on-error once the surface is clean. | |
| typecheck: | |
| name: Typecheck (mypy) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install runtime deps + mypy | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install 'flask>=3.0' 'fpdf2>=2.7' 'mypy>=1.10' | |
| - name: Run mypy | |
| # Transitional only (maintainer consensus): keeps CI green until `mypy` exits | |
| # zero on this repo — then delete this line so type errors fail the job. | |
| continue-on-error: true | |
| run: mypy --ignore-missing-imports --no-strict-optional --pretty . | |
| # ── Secret scan: gitleaks ───────────────────────────────────────────────── | |
| # Catches accidentally committed credentials. Runs over full git history | |
| # (fetch-depth: 0). No project-specific .gitleaks.toml — defaults cover | |
| # standard credential patterns (API keys, AWS, GitHub tokens, etc.). | |
| secret-scan: | |
| name: Secret scan (gitleaks) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install gitleaks | |
| run: | | |
| GITLEAKS_VERSION=8.21.2 | |
| base_url="https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}" | |
| tarball="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | |
| checksums="gitleaks_${GITLEAKS_VERSION}_checksums.txt" | |
| # Download tarball and checksums file to temp; retries prevent | |
| # transient 5xx failures. | |
| curl --fail --location --silent --show-error \ | |
| --retry 5 --retry-delay 2 --retry-all-errors \ | |
| -o "/tmp/${tarball}" "${base_url}/${tarball}" | |
| curl --fail --location --silent --show-error \ | |
| --retry 5 --retry-delay 2 --retry-all-errors \ | |
| -o "/tmp/${checksums}" "${base_url}/${checksums}" | |
| # Verify SHA-256 before extraction; fail and clean up on mismatch. | |
| expected=$(grep " ${tarball}$" "/tmp/${checksums}" | awk '{print $1}') | |
| if [ -z "${expected}" ]; then | |
| echo "::error::No checksum entry found for ${tarball}" >&2 | |
| rm -f "/tmp/${tarball}" "/tmp/${checksums}" | |
| exit 1 | |
| fi | |
| actual=$(sha256sum "/tmp/${tarball}" | awk '{print $1}') | |
| if [ "${expected}" != "${actual}" ]; then | |
| echo "::error::SHA-256 mismatch for ${tarball}: expected ${expected}, got ${actual}" >&2 | |
| rm -f "/tmp/${tarball}" "/tmp/${checksums}" | |
| exit 1 | |
| fi | |
| tar -xz -f "/tmp/${tarball}" gitleaks | |
| sudo mv gitleaks /usr/local/bin/gitleaks | |
| rm -f "/tmp/${tarball}" "/tmp/${checksums}" | |
| - name: Run gitleaks | |
| run: | | |
| gitleaks detect \ | |
| --source . \ | |
| --verbose \ | |
| --redact \ | |
| --exit-code 1 |