Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
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:
Comment thread
timon0305 marked this conversation as resolved.
# ── 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 }}
Comment on lines +19 to +25
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update matrix comments/name to match actual Ubuntu-only scope.

Line 19–23 describes cross-OS coverage, but Line 29 is Ubuntu-only. This is misleading during triage and maintenance.

✏️ Suggested patch
-  # ── Unit tests: matrix across OS and Python version ───────────────────────
+  # ── Unit tests: matrix across Python versions on Ubuntu ───────────────────
   # 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
+  # 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 }})
+    name: Unit tests (Ubuntu / Python ${{ matrix.python-version }})

Also applies to: 29-29

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/tests.yml around lines 19 - 25, The workflow comment and
job name claim cross-OS coverage but the job is Ubuntu-only; update the unit
test comment and the "unittest" job name to reflect Ubuntu-only scope (or
convert the matrix to include multiple OSes) so they are accurate: edit the
comment block above the unittest job and the job name string that currently uses
"${{ matrix.os }} / Python ${{ matrix.python-version }}" and either
remove/mutate references to matrix.os or adjust the matrix to include other
OSes; ensure consistency between the comment, the matrix definition, and the
unittest job name.

strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.11", "3.12", "3.13"]
Comment thread
bradjin8 marked this conversation as resolved.
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 .
Comment thread
bradjin8 marked this conversation as resolved.

# ── 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
Loading