From 42cc28ac6f0811b822e8021d97e5123ded6637c6 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 29 Oct 2026 17:49:26 -0300 Subject: [PATCH] =?UTF-8?q?Teste=20confere=20as=20permiss=C3=B5es=20do=20d?= =?UTF-8?q?ocs.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit O docs.yml só roda em push na main e em workflow_dispatch, então nenhum check de PR lia as permissões dele. O teste afirma que o workflow só concede contents: read, que o job deploy tem exatamente pages: write e id-token: write, e que nenhum outro job escreve (#268). --- CHANGELOG.md | 4 +++ tests/test_permissoes_do_docs_yml.py | 48 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 tests/test_permissoes_do_docs_yml.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 9372032b..9c2386aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR ## [Unreleased] +### Adicionado + +- Um teste confere as permissões do `docs.yml`, que nenhum check de PR executa: o workflow só concede `contents: read`, o job `deploy` tem exatamente `pages: write` e `id-token: write`, e nenhum outro job escreve. O PR que mexer nelas reprova no job de testes, antes do merge (#268). + ## [0.11.1] - 2026-10-29 ### Corrigido diff --git a/tests/test_permissoes_do_docs_yml.py b/tests/test_permissoes_do_docs_yml.py new file mode 100644 index 00000000..8f703013 --- /dev/null +++ b/tests/test_permissoes_do_docs_yml.py @@ -0,0 +1,48 @@ +"""Permissões do workflow que publica a documentação. + +O docs.yml só roda em push na main e em workflow_dispatch, então nenhum check +de PR o executa: sem este teste, um PR que mexa nas permissões passa verde, e o +deploy só falha, ou ganha escrita que não precisa, depois do merge. +""" + +from pathlib import Path + +import yaml + +DOCS_YML = Path(__file__).resolve().parents[1] / ".github" / "workflows" / "docs.yml" + + +def _workflow(): + return yaml.safe_load(DOCS_YML.read_text(encoding="utf-8")) + + +def _escopos_com_escrita(permissoes): + # O bloco permissions aceita o mapa escopo -> nível ou um atalho em texto + # ("read-all", "write-all"); o atalho de escrita conta como todos os escopos. + if isinstance(permissoes, str): + return ["write-all"] if permissoes == "write-all" else [] + return sorted(escopo for escopo, nivel in (permissoes or {}).items() if nivel == "write") + + +def test_workflow_so_concede_leitura_do_conteudo(): + assert _workflow().get("permissions") == {"contents": "read"} + + +def test_job_deploy_tem_exatamente_escrita_no_pages_e_token_oidc(): + deploy = _workflow()["jobs"]["deploy"] + + assert deploy.get("permissions") == {"pages": "write", "id-token": "write"} + + +def test_nenhum_job_alem_do_deploy_escreve(): + jobs = _workflow()["jobs"] + # Sem o build na lista, o laço abaixo poderia passar sem conferir nada. + assert "build" in jobs + + escritas = { + nome: escopos + for nome, job in jobs.items() + if nome != "deploy" and (escopos := _escopos_com_escrita(job.get("permissions"))) + } + + assert escritas == {}