Segurança do ciclo de desenvolvimento¶
Os controles que protegem um release do PEART rodam continuamente durante o desenvolvimento, não só na
hora do release. O invariante que guia isso é que make check é igual ao CI: os mesmos portões que um
mantenedor roda localmente são os que precisam passar em cada push para a main, então um commit que
reprovaria no CI reprova antes na máquina do desenvolvedor.
Os portões em cada commit¶
O make check roda, e o CI impõe:
- Análise estática de segurança com
gosec, ligada como linter dogolangci-lintao lado das passagens padrão de vet e lint. - Varredura de segredos com
gitleaks, para que uma credencial commitada por acidente reprove o build. - Varredura de vulnerabilidade em dependências com
govulnchecksobre toda a árvore de dependências. - Um portão de sintaxe de JavaScript que parseia cada script com um parser de ES-module em Go puro, pegando um script quebrado antes de sair (sem Node no pipeline).
- Checagens de comprimento de linha e formatação, e uma checagem de consistência de i18n entre os arquivos de locale.
Os testes abrangem testes unitários, testes table-driven para a lógica mais delicada, testes de
integração e testes de navegador. Um teste de navegador merece ser nomeado: ele carrega a casca real da
página num navegador real e reprova se a Content-Security-Policy que o servidor envia é de fato violada
no console, não apenas ausente do fonte da página, para que a CSP sobre a qual toda a segurança do
front-end se apoia não possa regredir em silêncio. O código do próprio projeto carrega zero ocorrências
de innerHTML, unsafeHTML ou unsafeStatic, uma propriedade que é medida, não presumida.
Build e distribuição¶
Os binários são Go cross-compilado puro, sem CGO (ADR 0004), compilados com -trimpath para que nenhum
caminho da máquina de build vaze no artefato. Mudanças de schema do banco são migrações forward-only,
revisáveis uma a uma.
Bill of materials do software¶
Cada release publica um SBOM em CycloneDX. Ele é produzido pelo cyclonedx-gomod para o grafo de
módulos Go, e depois um segundo passo dobra nele os pacotes de front-end vendorizados sob web/vendor/
(o Lit e um gerador de QR-code) como componentes CycloneDX também, então o SBOM publicado lista um
pacote npm vendorizado do mesmo jeito que lista um módulo Go. O bill of materials fica, portanto,
completo nos dois ecossistemas de linguagem, não só no lado Go.
Releases assinados e atestados¶
Os releases são assinados sem chave (keyless) com o cosign, usando o token OpenID Connect de curta vida do próprio fluxo de release, em vez de qualquer chave privada de longa vida que o projeto teria que proteger ou rotacionar. As assinaturas são publicadas no log de transparência público do Sigstore.
Assinados no release: o manifesto de checksums, o SBOM e a imagem de container (assinada pelo digest do conteúdo, não por uma tag que se move). Qualquer um pode verificar o manifesto de checksums contra a identidade do fluxo de release:
cosign verify-blob \
--certificate-identity-regexp 'https://github.com/mentesan/peart/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--signature checksums.txt.sig --certificate checksums.txt.pem \
checksums.txt
e a imagem pelo digest:
cosign verify \
--certificate-identity-regexp 'https://github.com/mentesan/peart/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/mentesan/peart@<digest>
A proveniência do front-end vendorizado é hoje afirmada pelo web/vendor/MANIFEST.md; verificar cada
arquivo vendorizado por hash contra o pacote de origem no CI é um endurecimento planejado.