diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0152620..0b1e6db 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,6 +9,7 @@ updates: semver-patch-days: 7 semver-minor-days: 14 semver-major-days: 30 + default-days: 7 commit-message: prefix: "chore" include: "scope" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 13b5fe6..21c2174 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,5 +1,8 @@ name: "CodeQL Advanced" +permissions: + contents: read + on: push: branches: [ "master" ] @@ -9,13 +12,16 @@ on: - cron: '36 16 * * 6' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: analyze: name: Analyze (${{ matrix.language }}) runs-on: ubuntu-26.04 permissions: - # required for all workflows - security-events: write + security-events: write # Required for CodeQL to upload results to GitHub Security and Quality tab strategy: fail-fast: false @@ -29,6 +35,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 7.0.0 + with: + persist-credentials: false # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9b4c7f7..9744bce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,10 @@ on: branches: [ master ] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: tests: timeout-minutes: 20 @@ -54,11 +58,13 @@ jobs: - name: Clone repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 7.0.0 with: - persist-credentials: true # Required for Codecov OIDC authentication + persist-credentials: false - name: Test with pytest + env: + PYTHON_VERSION: ${{ matrix.python-version }} run: | - uv run --python ${{ matrix.python-version }} --group tests --locked pytest + uv run --python "$PYTHON_VERSION" --group tests --locked pytest - name: Upload coverage to Codecov if: matrix.os == 'ubuntu-26.04' && matrix.python-version == '3.14' diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000..0c6d67d --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,35 @@ +name: Zizmor + +permissions: + contents: read + +on: + push: + branches: [ master ] + paths: [ '.github/workflows/**' ] + pull_request: + branches: [ master ] + paths: [ '.github/workflows/**' ] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + zizmor: + timeout-minutes: 10 + name: Lint GitHub Actions with zizmor + runs-on: ubuntu-26.04 + steps: + - name: Install uv + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # 8.2.0 + + - name: Clone repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 7.0.0 + with: + persist-credentials: false + + - name: Run zizmor + run: | + make zizmor-check diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b40a5f7..a414c0b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,6 +16,13 @@ repos: - id: mypy args: [--config-file=pyproject.toml] + # zizmor for github actions linting + - repo: https://github.com/zizmorcore/zizmor-pre-commit + rev: v1.26.1 # Keep in sync zizmor version with pyproject.toml + hooks: + - id: zizmor + args: [--no-progress, --fix, --persona=auditor] + # Standard pre-commit hooks - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 diff --git a/Makefile b/Makefile index 724e2a6..5bcff4d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: default install format fix ruff-check mypy-check check benchmark-test integration-test property-test unit-test test doc publish clean +.PHONY: default install format fix ruff-check mypy-check zizmor-check check benchmark-test integration-test property-test unit-test test doc publish clean UV := $(shell command -v uv 2>/dev/null || true) ifeq ($(UV),) @@ -6,7 +6,7 @@ $(warning uv not found. Install uv (curl -LsSf https://astral.sh/uv/install.sh | endif default: - @echo "Usage: make [install|format|fix|ruff-check|mypy-check|check|benchmark-test|integration-test|property-test|unit-test|test|doc|publish|clean]" + @echo "Usage: make [install|format|fix|ruff-check|mypy-check|zizmor-check|check|benchmark-test|integration-test|property-test|unit-test|test|doc|publish|clean]" @exit 1 install: @@ -17,6 +17,7 @@ format: fix: uv run --group quality --locked ruff check --fix + uv run --group quality --locked zizmor --collect=all --no-progress --fix --persona=auditor . ruff-check: uv run --group quality --locked ruff check @@ -25,9 +26,13 @@ ruff-check: mypy-check: uv run --group tests --group types --group quality --locked mypy +zizmor-check: + uv run --group quality --locked zizmor --collect=all --no-progress --persona=auditor . + check: make ruff-check make mypy-check + make zizmor-check benchmark-test: uv run --group tests --locked pytest -m perf diff --git a/make.bat b/make.bat index fc49e02..dfd9942 100644 --- a/make.bat +++ b/make.bat @@ -12,6 +12,7 @@ if "%1"=="format" goto format if "%1"=="fix" goto fix if "%1"=="ruff-check" goto ruff-check if "%1"=="mypy-check" goto mypy-check +if "%1"=="zizmor-check" goto zizmor-check if "%1"=="check" goto check if "%1"=="benchmark-test" goto benchmark-test if "%1"=="integration-test" goto integration-test @@ -22,7 +23,7 @@ if "%1"=="doc" goto doc if "%1"=="publish" goto publish if "%1"=="clean" goto clean -echo Usage: make.bat [install^|format^|fix^|ruff-check^|mypy-check^|check^|benchmark-test^|integration-test^|property-test^|unit-test^|test^|doc^|publish^|clean] +echo Usage: make.bat [install^|format^|fix^|ruff-check^|mypy-check^|zizmor-check^|check^|benchmark-test^|integration-test^|property-test^|unit-test^|test^|doc^|publish^|clean] exit /b 1 :install @@ -35,6 +36,8 @@ exit /b %errorlevel% :fix uv run --group quality --locked ruff check --fix +if errorlevel 1 exit /b %errorlevel% +uv run --group quality --locked zizmor --collect=all --no-progress --fix --persona=auditor . exit /b %errorlevel% :ruff-check @@ -48,10 +51,16 @@ exit /b %errorlevel% uv run --group tests --group types --group quality --locked mypy exit /b %errorlevel% +:zizmor-check +uv run --group quality --locked zizmor --collect=all --no-progress --persona=auditor . +exit /b %errorlevel% + :check call :ruff-check if errorlevel 1 exit /b %errorlevel% call :mypy-check +if errorlevel 1 exit /b %errorlevel% +call :zizmor-check exit /b %errorlevel% :benchmark-test diff --git a/pyproject.toml b/pyproject.toml index e540e9f..a454c42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,6 +64,8 @@ quality = [ "mypy==2.1.0", # Keep in sync ruff version with .pre-commit-config.yaml "ruff==0.15.16", + # Keep in sync zizmor version with .pre-commit-config.yaml + "zizmor==1.26.1" ] diff --git a/uv.lock b/uv.lock index 07ecf5e..d3afbd0 100644 --- a/uv.lock +++ b/uv.lock @@ -468,6 +468,7 @@ docs = [ quality = [ { name = "mypy" }, { name = "ruff" }, + { name = "zizmor" }, ] tests = [ { name = "hypothesis" }, @@ -499,6 +500,7 @@ docs = [ quality = [ { name = "mypy", specifier = "==2.1.0" }, { name = "ruff", specifier = "==0.15.16" }, + { name = "zizmor", specifier = "==1.26.1" }, ] tests = [ { name = "hypothesis" }, @@ -1255,3 +1257,21 @@ sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e wheels = [ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, ] + +[[package]] +name = "zizmor" +version = "1.26.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/a0/a29b38e24981b4bb41db4f292b2c9fb9ddf8b05d6b724abddd7bd108b621/zizmor-1.26.1.tar.gz", hash = "sha256:0c2cc575007a4db99d89d5acc6120cfa7b61504bc2394c3b50af348c73f1916e", size = 535275, upload-time = "2026-06-21T02:47:21.265Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/a9/2f47f7db8db9491025e00a7f1a0f25d32b642c0285b2fe070ac63e679b47/zizmor-1.26.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7ea21ca959c8e888de238fee81d73a1fdf89a82067eac75b8f1acdbd23e2eeaf", size = 9086061, upload-time = "2026-06-21T02:46:57.492Z" }, + { url = "https://files.pythonhosted.org/packages/58/92/cf6801f01e1d65cbda89a2e2926ea42caf1daad9ffa3f1fc88e4c68f48a9/zizmor-1.26.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:78083b495593f8b0b9dec14036a0836a5afcddda8a40738336ff4e399476b741", size = 8626865, upload-time = "2026-06-21T02:47:00.323Z" }, + { url = "https://files.pythonhosted.org/packages/b4/b1/ff38fc2921f1fb13244bb3a3642c4b45ecf3946c279942aafcb5dbf55a57/zizmor-1.26.1-py3-none-manylinux_2_24_aarch64.whl", hash = "sha256:bb7ebbe565a3742eb49a590352127ad549bb122b9b4ff9424ebab7525fa3b6b6", size = 8843965, upload-time = "2026-06-21T02:47:03.318Z" }, + { url = "https://files.pythonhosted.org/packages/3d/06/c07fd0eeef0427d93e99d552d5386526fbcd0bf05fc95cd37bdc6229fccb/zizmor-1.26.1-py3-none-manylinux_2_28_armv7l.whl", hash = "sha256:d3049010b6bd6f849413b6d20c28e0c677b90e0a5b2bc73cbee7f7bd86dc5828", size = 8386985, upload-time = "2026-06-21T02:47:05.741Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2b/61ab13d45d6ce57ef5a08bb3246981f62e30bb4938098b17bb7b88110b79/zizmor-1.26.1-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:6a958d8a0941d7e1d0de8436670b5cb7fc64c8028b4d16e3f519ccc77f953cef", size = 9257232, upload-time = "2026-06-21T02:47:07.941Z" }, + { url = "https://files.pythonhosted.org/packages/e3/ad/bd74a96cb02045414ec5b573cd97ff3b82a97fd0bd6658f93c36a011c439/zizmor-1.26.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d2744cdf944436ca7a009ae8b626a017a40381ec990216abd6cf6b8beb23323a", size = 8873798, upload-time = "2026-06-21T02:47:10.472Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7e/fb3d608ee11e2f619d43ad93bab46eb7b32769fa82b1d86fd23f27c2585b/zizmor-1.26.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:44099f426af9da750ff9f548a0084e11d7d83e0158fe1a2778672398d728efdd", size = 8350857, upload-time = "2026-06-21T02:47:12.748Z" }, + { url = "https://files.pythonhosted.org/packages/27/cc/82d7a838c2d490071555c364f90eb851044b3eeefc1d68612179a2cd1ae5/zizmor-1.26.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8313cc264dec792f00a7328eb7c8e89e7d62d54f950fc897d1e6a5a6e5762203", size = 9351148, upload-time = "2026-06-21T02:47:14.777Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ee/d2a2301f30b9e1bf0d721bfd31739acd71e048757f9ba79279583eb30ac0/zizmor-1.26.1-py3-none-win32.whl", hash = "sha256:c96d7787d69fb298eae939e00dfdf7f534d7dfbd9cc17ab442c0650a56851415", size = 7531021, upload-time = "2026-06-21T02:47:17.247Z" }, + { url = "https://files.pythonhosted.org/packages/91/58/ad561f3a5057d3c0f152002e180a3a5745e72ea9d69bf66450ef9f5d3fe5/zizmor-1.26.1-py3-none-win_amd64.whl", hash = "sha256:0a05acf6068609fb6df3b137276cf18a686226a1e0e207941cb34a85929f16cf", size = 8616584, upload-time = "2026-06-21T02:47:19.094Z" }, +]