diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 718572b..91f1dcf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,3 +5,5 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 13e9368..c0e3499 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,27 +14,35 @@ on: - '*' merge_group: +permissions: {} + jobs: run-type-checking: name: Run tests for type-checking runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v7 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: version: "0.9.9" enable-cache: true - name: Install just - uses: extractions/setup-just@v3 + uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b # v3 - run: just typing run-tests: name: Run tests for ${{ matrix.os }} on ${{ matrix.python-version }} runs-on: ${{ matrix.os }} + permissions: + contents: read strategy: fail-fast: false @@ -43,17 +51,19 @@ jobs: python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: - - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v7 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: version: "0.9.9" enable-cache: true python-version: ${{ matrix.python-version }} - name: Install just - uses: extractions/setup-just@v3 + uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b # v3 - name: Run end-to-end tests run: just test - name: Upload coverage reports of tests. if: runner.os == 'Linux' && matrix.python-version == '3.11' - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000..9e959bc --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,48 @@ +name: zizmor + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + schedule: + - cron: '0 7 * * 1' + workflow_dispatch: + +permissions: {} + +jobs: + zizmor: + name: Scan GitHub Actions + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 + with: + enable-cache: true + python-version: '3.13' + + - name: Run zizmor + run: uvx --from zizmor zizmor --format=github . + + - name: Generate SARIF report + if: always() + run: uvx --from zizmor zizmor --format=sarif --no-exit-codes . > zizmor.sarif + + - name: Upload SARIF report + if: > + always() && + (github.event_name != 'pull_request' || + github.event.pull_request.head.repo.full_name == github.repository) + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4 + with: + sarif_file: zizmor.sarif diff --git a/{{cookiecutter.package_name}}/.github/dependabot.yml b/{{cookiecutter.package_name}}/.github/dependabot.yml index 718572b..91f1dcf 100644 --- a/{{cookiecutter.package_name}}/.github/dependabot.yml +++ b/{{cookiecutter.package_name}}/.github/dependabot.yml @@ -5,3 +5,5 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 diff --git a/{{cookiecutter.package_name}}/.github/workflows/main.yml b/{{cookiecutter.package_name}}/.github/workflows/main.yml index e7b0b68..a22a9e1 100644 --- a/{{cookiecutter.package_name}}/.github/workflows/main.yml +++ b/{{cookiecutter.package_name}}/.github/workflows/main.yml @@ -14,27 +14,35 @@ on: - '*' merge_group: +permissions: {} + jobs: run-type-checking: name: Run tests for type-checking runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v7 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: version: "0.9.9" enable-cache: true - name: Install just - uses: extractions/setup-just@v3 + uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b # v3 - run: just typing run-tests: name: Run tests for ${{ matrix.os }} on ${{ matrix.python-version }} runs-on: ${{ matrix.os }} + permissions: + contents: read strategy: fail-fast: false @@ -43,17 +51,19 @@ jobs: python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v7 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: version: "0.9.9" enable-cache: true python-version: ${{ matrix.python-version }} - name: Install just - uses: extractions/setup-just@v3 + uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b # v3 - name: Run tests and doctests run: just test-cov - name: Upload coverage report if: runner.os == 'Linux' && matrix.python-version == '3.11' - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5 diff --git a/{{cookiecutter.package_name}}/.github/workflows/publish-to-pypi.yml b/{{cookiecutter.package_name}}/.github/workflows/publish-to-pypi.yml index cef64ee..fd9cf3b 100644 --- a/{{cookiecutter.package_name}}/.github/workflows/publish-to-pypi.yml +++ b/{{cookiecutter.package_name}}/.github/workflows/publish-to-pypi.yml @@ -1,36 +1,96 @@ -name: PyPI +name: Publish Python distribution to PyPI on: push +permissions: {} + jobs: - build-n-publish: - name: Build and publish Python 🐍 distributions 📦 to PyPI + build: + name: Build distribution runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master + permissions: + contents: read - - name: Set up Python 3.8 - uses: actions/setup-python@v1 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: - python-version: 3.8 - + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 + with: + python-version: "3.x" - name: Install pypa/build run: >- - python -m + python3 -m pip install build --user - - name: Build a binary wheel and a source tarball - run: >- - python -m - build - --sdist - --wheel - --outdir dist/ + run: python3 -m build + - name: Store the distribution packages + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: python-package-distributions + path: dist/ + + publish-to-pypi: + name: Publish Python distribution to PyPI + if: startsWith(github.ref, 'refs/tags/') + needs: + - build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/{{ cookiecutter.package_name }} + permissions: + id-token: write + + steps: + - name: Download all the dists + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1 + + github-release: + name: Sign the distribution and upload it to GitHub Release + needs: + - publish-to-pypi + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write - - name: Publish distribution 📦 to PyPI - if: startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@master + steps: + - name: Download all the dists + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: python-package-distributions + path: dist/ + - name: Sign the dists with Sigstore + uses: sigstore/gh-action-sigstore-python@a5caf349bc536fbef3668a10ed7f5cd309a4b53d # v3.2.0 with: - password: ${{ secrets.PYPI_API_TOKEN }} + inputs: >- + ./dist/*.tar.gz + ./dist/*.whl + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + REPOSITORY: ${{ github.repository }} + run: >- + gh release create + "$RELEASE_TAG" + --repo "$REPOSITORY" + --notes "" + - name: Upload artifact signatures to GitHub Release + env: + GITHUB_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + REPOSITORY: ${{ github.repository }} + run: >- + gh release upload + "$RELEASE_TAG" dist/** + --repo "$REPOSITORY" diff --git a/{{cookiecutter.package_name}}/.github/workflows/zizmor.yml b/{{cookiecutter.package_name}}/.github/workflows/zizmor.yml new file mode 100644 index 0000000..9e959bc --- /dev/null +++ b/{{cookiecutter.package_name}}/.github/workflows/zizmor.yml @@ -0,0 +1,48 @@ +name: zizmor + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + schedule: + - cron: '0 7 * * 1' + workflow_dispatch: + +permissions: {} + +jobs: + zizmor: + name: Scan GitHub Actions + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 + with: + enable-cache: true + python-version: '3.13' + + - name: Run zizmor + run: uvx --from zizmor zizmor --format=github . + + - name: Generate SARIF report + if: always() + run: uvx --from zizmor zizmor --format=sarif --no-exit-codes . > zizmor.sarif + + - name: Upload SARIF report + if: > + always() && + (github.event_name != 'pull_request' || + github.event.pull_request.head.repo.full_name == github.repository) + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4 + with: + sarif_file: zizmor.sarif