diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..645c171 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..c9e8bb0 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,44 @@ +name: Security Scanning + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '0 6 * * 1' # Weekly on Mondays + workflow_dispatch: + +jobs: + codeql: + name: CodeQL Analysis + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + steps: + - uses: actions/checkout@v4 + - uses: github/codeql-action/init@v4 + with: + languages: python + - uses: github/codeql-action/analyze@v4 + + pip-audit: + name: Dependency Vulnerability Scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install system dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y libgirepository1.0-dev libcairo2-dev pkg-config \ + python3-dev libdbus-1-dev gir1.2-gtk-4.0 + - name: Install project + run: pip install -e . + - uses: pypa/gh-action-pip-audit@v1.1.0 + with: + local: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e9b8091 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +repos: + - repo: https://github.com/PyCQA/bandit + rev: 1.9.4 + hooks: + - id: bandit + name: bandit (security linter) + args: ["-r", "-ll"] + # -r recursive, -ll report medium+ severity + + - repo: local + hooks: + - id: pip-audit + name: pip-audit (dependency scan) + language: system + entry: pip-audit + args: ["-r", "requirements.txt", "--no-deps"] + pass_filenames: false + # language: system uses the system Python, giving pip access to system + # libs (libgirepository, Cairo) needed to build PyGObject metadata. + # --no-deps checks only direct dependencies from requirements.txt + # (which mirrors install_requires in setup.py), not transitive deps. + # Transitive dependency CVEs are caught by pip-audit in CI where the + # full project is installed in a clean runner with system libs present. + # Requires pip-audit in the active environment: pip install pip-audit diff --git a/README.md b/README.md index eb59335..0cd9330 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,42 @@ pip install -e . At this point, hints should be installed locally in the virtual environment, you can run `hints` in your shell to launch it. Any edits you make to the source code will automatically update the installation. For future development work, you can simply re-enable the virtual environment (step 2). +## Pre-commit validation + +hints uses [pre-commit](https://pre-commit.com) to run security checks locally before each commit: + +- **bandit** — static analysis (SAST) for Python security issues, runs on staged files. +- **pip-audit** — dependency vulnerability scan against the [OSV database](https://osv.dev), runs against `requirements.txt`. + +### Setup + +4. Install pre-commit: + +``` +pip install pre-commit +``` + +5. Install pip-audit: + +``` +pip install pip-audit +``` + +6. Install the git hooks: + +``` +pre-commit install +``` + +The hooks will now run automatically on every `git commit`. You can also run them manually at any time: + +``` +pre-commit run --all-files +``` + +> [!NOTE] +> `PyGObject` is excluded from `requirements.txt` used by pip-audit because it requires `gobject-introspection` system headers to build package metadata, which are not universally available. It is covered by pip-audit in CI. + ## Development tips - If you are making updates that impact hints, you will most likely need to test displaying hints and might find yourself executing hints but not being quick enough to switch to a window to see hints. To get around this, you can execute `hints` with a short pause in your shell: `sleep 0.5; hints`. This way you can have time to switch to a window and see any errors / logs in your shell. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9700f3a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +# Runtime dependencies — mirrors install_requires in setup.py. +# Kept in sync manually; used by pip-audit for local dependency scanning. +# +# PyGObject is intentionally excluded: it requires gobject-introspection system +# headers to build metadata, which are not universally available. It is covered +# by pip-audit in CI where system libs are installed explicitly. +pillow +pyscreenshot +opencv-python +evdev +dbus-python +rich