diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 69332808..6c78952d 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -14,8 +14,6 @@ on: permissions: contents: read - pages: write - id-token: write concurrency: group: "pages" @@ -25,15 +23,17 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.13' - name: Setup uv - uses: astral-sh/setup-uv@v10.3.0 + uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: enable-cache: true @@ -45,11 +45,17 @@ jobs: run: cp site/sitemap.xml site/en/sitemap.xml - name: Upload artifact - uses: actions/upload-pages-artifact@v5 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: ./site deploy: + # Permissões de job substituem as do workflow, e este job não faz + # checkout: precisa só de escrever no Pages e do token OIDC com que o + # deploy-pages prova que a publicação vem deste repositório. + permissions: + pages: write + id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} @@ -58,4 +64,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v5 + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3c36121d..0044baa4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,18 +18,31 @@ jobs: env: EXTRAS: --extra dev --extra all --extra search-all --extra polars --extra excel --extra codex steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.13' - name: Setup uv - uses: astral-sh/setup-uv@v10.3.0 + uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: enable-cache: true + # Auditoria de segurança dos workflows. Com --offline, o zizmor roda só + # as auditorias que leem os arquivos. As online consultam a API do GitHub + # a cada execução e ficam de fora: impostor-commit, ref-confusion, + # known-vulnerable-actions, stale-action-refs e ref-version-mismatch. Os + # SHAs fixados foram conferidos contra as tags quando entraram. A versão + # fica fixada porque uma versão nova pode trazer auditoria nova e + # reprovar um PR que não mexeu nos workflows, e o Dependabot não atualiza + # versão escrita dentro de run:. + - name: zizmor + run: uvx zizmor@1.30.1 --offline .github/workflows + - name: Ruff format run: uv run --python 3.13 $EXTRAS ruff format --check src tests @@ -52,15 +65,17 @@ jobs: matrix: python-version: ['3.11', '3.13', '3.14'] steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: ${{ matrix.python-version }} - name: Setup uv - uses: astral-sh/setup-uv@v10.3.0 + uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: enable-cache: true @@ -89,7 +104,7 @@ jobs: pytest --cov=dataframeit --cov-branch --cov-report= --cov-fail-under=0 - name: Upload coverage data - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: coverage-unit-${{ matrix.python-version }} path: .coverage.unit-${{ matrix.python-version }} @@ -110,15 +125,17 @@ jobs: matrix: extras: ['', 'all excel polars search-all'] steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.11' - name: Setup uv - uses: astral-sh/setup-uv@v10.3.0 + uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: enable-cache: true @@ -142,15 +159,17 @@ jobs: matrix: python-version: ['3.11', '3.13', '3.14'] steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: ${{ matrix.python-version }} - name: Setup uv - uses: astral-sh/setup-uv@v10.3.0 + uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: enable-cache: true @@ -163,7 +182,7 @@ jobs: pytest --cov=dataframeit --cov-branch --cov-report= --cov-fail-under=0 - name: Upload coverage data - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: coverage-codex-${{ matrix.python-version }} path: .coverage.codex-${{ matrix.python-version }} @@ -178,20 +197,22 @@ jobs: needs: [unit, codex-provider] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.13' - name: Setup uv - uses: astral-sh/setup-uv@v10.3.0 + uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: enable-cache: true - name: Download coverage data - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: pattern: coverage-* merge-multiple: true @@ -204,15 +225,17 @@ jobs: codex-windows: runs-on: windows-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.13' - name: Setup uv - uses: astral-sh/setup-uv@v10.3.0 + uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: enable-cache: true @@ -226,15 +249,17 @@ jobs: if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.13' - name: Setup uv - uses: astral-sh/setup-uv@v10.3.0 + uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: enable-cache: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fd96c8ff..4c284c4c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,9 @@ # Os hooks rodam as mesmas versões do extra dev do pyproject.toml, pelo uv, e # o job quality do CI (tests.yml) roda os mesmos comandos. # Instalação: uv run --extra dev pre-commit install -# Os hooks disparam com mudanças em src/ e tests/, as pastas que o CI confere. +# Os hooks disparam com mudanças em src/ e tests/. Os workflows de +# .github/workflows/ não têm hook: o passo zizmor do job quality os confere, e +# o comando dele roda também na máquina local. files: ^(src|tests)/ repos: - repo: local diff --git a/CHANGELOG.md b/CHANGELOG.md index 97653918..059aabce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,10 @@ e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR - `depends_on` em tupla vale como a lista. Antes, era descartado em silêncio, e o aviso dizia que `depends_on` faltava. Forma diferente de texto, lista ou tupla de nomes levanta `ValueError` antes de processar (#150). - A configuração por campo declarada num modelo dentro de `Annotated` aninhado, como `list[Annotated[list["X"], ...]]`, é encontrada pela varredura e pelas validações. A referência adiantada dentro do `Annotated` é resolvida, e os metadados ficam como estavam (#151). +### Segurança + +- Os workflows do CI fixam cada action pelo SHA do commit, com a versão em comentário; o `actions/checkout` deixa de gravar o token do GitHub no `.git/config` do runner (`persist-credentials: false`); e, no `docs.yml`, só o job que publica tem `pages: write` e `id-token: write`. O job `quality` roda o `zizmor`, que reprova a action referida por tag ou branch no lugar do SHA, o `actions/checkout` sem a chave `persist-credentials` e a permissão de escrita no nível do workflow (#209). + ## [0.10.0] - 2026-09-24 ### Adicionado diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 32a21724..00616331 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ Os testes não chamam nenhum provider de verdade e não precisam de chave de API 1. Abra uma issue antes de uma mudança grande, para combinar o desenho. 2. Crie uma branch a partir da `main` com o prefixo do tipo de mudança: `feature/`, `fix/`, `docs/` ou `refactor/`. 3. Escreva o teste junto com a mudança. Uma correção de bug vem com o teste que falhava antes dela. -4. Abra o PR contra a `main`. O CI roda lint, testes em Python 3.11, 3.13 e 3.14, os testes com as versões mínimas das dependências e o build da documentação. +4. Abra o PR contra a `main`. O CI roda lint, a auditoria dos workflows pelo `zizmor`, testes em Python 3.11, 3.13 e 3.14, os testes com as versões mínimas das dependências e o build da documentação. ## Convenções @@ -33,6 +33,8 @@ As regras de versionamento, de `CHANGELOG.md` e de escrita de documentação est - A documentação descreve o estado atual. O histórico fica no `CHANGELOG.md` e no git, sem notas do tipo "desde a versão X". - O número de versão só muda na preparação de um release. +Os workflows de `.github/workflows/` fixam cada action pelo SHA do commit, com a versão em comentário (`uses: dono/action@ # v1.2.3`), e o `actions/checkout` leva `persist-credentials: false`. O passo `zizmor` do job `quality`, em `tests.yml`, reprova a action referida por tag ou branch no lugar do SHA, o `actions/checkout` sem a chave `persist-credentials` e a permissão de escrita no nível do workflow. O `zizmor --offline` não confere o comentário de versão e aceita `persist-credentials: true`, e essas duas partes da convenção ficam a cargo da revisão do PR. O mesmo comando do passo roda na máquina local. + A documentação tem duas árvores com o mesmo conteúdo: `docs/` em português, que é o idioma padrão do site, e `docs/en/` em inglês. Uma mudança numa página vale para as duas. ## Exemplos