Pular para o conteúdo

Segurança e operações do builder de backport

Ferramenta de build — NÃO é uma dependência de runtime. Esta página explica como operar o pipeline de build e como confiar nele. A postura de segurança do próprio engine do Portable Document Format (PDF) é documentada junto ao engine, não aqui.

O builder transforma código-fonte que ele não escreve e emite uma distribuição que ele não desenvolve. O modelo de segurança dele decorre desse limite. O limite de confiança é o checkout do código-fonte e a toolchain. O artefato emitido é somente leitura e produzido por máquina. A separação de licenciamento entre os pacotes público e Pro é fixada em código.

O builder recebe como entradas os repositórios de código-fonte e a toolchain fixada. Ele produz um artefato derivado. Três propriedades se aplicam:

  • A distribuição gerada é somente leitura e produzida por máquina. Ela é publicada como tags de versão, não como branches deste repositório. Desenvolvimento, relatórios de bug e solicitações de funcionalidades vão para os repositórios de código-fonte originais nextpdf/*, nunca para a árvore gerada. Verificado em relação ao bloco de atenção do README.md do projeto e ao .github/workflows/build.yml (o release faz commit e adiciona tags à árvore gerada a partir do zero).
  • O escopo do token de release é restrito. O secrets.BACKPORT_TRIGGER_TOKEN autoriza a clonagem dos repositórios de código-fonte na tag de release. Ele é referenciado apenas nas etapas de checkout do código-fonte. Verificado em relação ao build.yml (uso de GH_TOKEN).
  • A divisão de runners da integração contínua (CI) é intencional. Eventos confiáveis rodam em runners de PHP self-hosted; pull requests de forks e execuções do Dependabot são forçados a usar runners hospedados pelo GitHub. Código não confiável nunca é executado no pool de runners confiáveis. Verificado em relação ao .github/workflows/0-ci.yml (a condicional runs-on).
  • A toolchain é restringida no composer.json. Ela usa Rector ^2.0, PHPStan ^2.1, PHPUnit ^13.0 e o conjunto symfony/polyfill-*. O builder não tem dependência de runtime do NextPDF; portanto, um pacote de runtime do NextPDF comprometido não consegue alcançar o builder. Verificado em relação ao composer.json.
  • As atualizações de dependências são conduzidas por bot e passam por gate. Há uma configuração do Dependabot e um workflow de auto-merge. As execuções do Dependabot são fixadas em runners hospedados pelo GitHub e, ainda assim, passam pelo gate completo de CI (PHPStan, testes, dry-run) antes do merge. Verificado em relação ao .github/dependabot.yml e ao .github/workflows/0-ci.yml, 9-dependabot-auto-merge.yml.
  • A saída exclui o estado de build. O arquivo de release é compactado com vendor/ e .git/ excluídos. O artefato publicado carrega o código-fonte e o manifesto gerado, não a própria árvore de dependências do builder. Verificado em relação ao build.yml (zip ... -x '*/vendor/*' '*/.git/*').
  • A análise estática funciona como gate para o código de build. O composer analyse executa o PHPStan no nível 10 sobre rector/rules e scripts a cada push e pull request para qualquer um dos branches permanentes. Ela é executada antes de qualquer dry-run. Verificado em relação ao composer.json e ao 0-ci.yml.

O script de build não faz a verificação de sintaxe da saída localmente porque o host de build roda um PHP mais novo que o alvo. O gate definitivo fica no workflow de release. Depois do build, o runner alterna para o PHP alvo e executa php -l em output/src, fazendo o release falhar diante de qualquer erro de parse ou erro fatal. Em seguida, o artefato é instalado e exercitado em toda a matriz de validação — PHP 8.1 a 8.4 para a faixa do PHP 8.1, e PHP 7.4 e 8.0 para a faixa do PHP 7.4. Uma distribuição que um runtime alvo rejeitaria não chega a um release. Verificado em relação ao scripts/build.php (validateOutput()) e ao .github/workflows/build.yml (os jobs de verificação de sintaxe e validate-*).

Esta é uma garantia de comportamento observado, limitada aos runtimes que o pipeline exercita. Não é uma certificação de conformidade. Ela não afirma a correção do programa transformado além da aceitação de sintaxe e da própria suíte de testes do projeto.

Os dois pacotes produzidos têm licenças diferentes, fixadas em scripts/adjust-composer.php:

PacoteCampo de licençaDefinido por
nextpdf/backportApache-2.0generatePublicComposer()
nextpdf/backport-proproprietarygenerateProComposer()

O próprio repositório do builder é Apache-2.0 (composer.jsonlicense). O CHANGELOG.md dele registra um relicenciamento anterior de LGPL-3.0-or-later para Apache-2.0. As versões publicadas antes dessa mudança permanecem sob a licença anterior e continuam recuperáveis, enquanto toda versão nova é Apache-2.0. A distribuição Pro é proprietária, produzida apenas para o alvo PHP 8.1, e requer phpseclib/phpseclib ^3.0. Verificado em relação ao CHANGELOG.md, ao composer.json e ao scripts/adjust-composer.php.

O que o pipeline garante, limitado ao que o código impõe:

  • Parada na primeira falha. O build é abortado no primeiro estágio que falha, com um erro nomeado. Uma distribuição parcial nunca é lançada porque os jobs de release dependem de um build e de uma validação bem-sucedidos. Verificado em relação ao scripts/build.php (step()) e ao build.yml (campo needs do job).
  • Builds serializados. O grupo de concorrência backport-build com cancel-in-progress: false impede que dois releases de código-fonte disputem a mesma tag de release. Verificado em relação ao build.yml.
  • Entradas reproduzíveis. O pipeline clona cada repositório de código-fonte na tag de release exata antes de executar o build. Verificado em relação ao build.yml (--branch "${TAG}").

O que ele não afirma:

  • Ele não certifica conformidade com padrões, compatibilidade completa com versões do PHP nem a correção do programa transformado além da aceitação de sintaxe e da suíte de testes.
  • O downgrade remove a imutabilidade imposta pelo runtime (remoção de readonly). Código que dependia do runtime para rejeitar uma escrita em uma propriedade readonly perde essa defesa na saída convertida. Essa é uma troca documentada e intencional em favor da segurança do clone-with — consulte /integrations/backport/troubleshooting/.

Os problemas de segurança no builder seguem o SECURITY.md do repositório: reporte-os por meio de um GitHub Security Advisory ou do contato de segurança, não em uma issue pública. Abra issues sobre o código gerado nos repositórios de código-fonte originais, porque a árvore gerada é produzida por máquina e não é alvo de desenvolvimento. Verificado em relação ao SECURITY.md e ao README.md do projeto.

  • /integrations/backport/overview/ — o que é o builder e o que ele produz.
  • /integrations/backport/production-usage/ — como operar o pipeline de release.