stillwater

Projetos que seguem as melhores práticas abaixo podem se autocertificar voluntariamente e mostrar que alcançaram um selo de melhores práticas da Open Source Security Foundation (OpenSSF).

Não existe um conjunto de práticas que possa garantir que o software nunca terá defeitos ou vulnerabilidades; mesmo métodos formais podem falhar se as especificações ou suposições estiverem erradas. Nem existe qualquer conjunto de práticas que possa garantir que um projeto sustentará uma comunidade de desenvolvimento saudável e bem-funcionada. No entanto, seguir as melhores práticas pode ajudar a melhorar os resultados dos projetos. Por exemplo, algumas práticas permitem revisão multipessoal antes do lançamento, o que pode ajudar a encontrar vulnerabilidades técnicas difíceis de encontrar e ajudar a construir confiança e desejo de interação repetida entre desenvolvedores de diferentes empresas. Para ganhar um selo, todos os critérios DEVE e NÃO DEVE devem ser atendidos, todos os critérios DEVERIA devem ser atendidos OU não atendidos com justificativa, e todos os critérios SUGERIDO devem ser atendidos OU não atendidos (queremos que sejam considerados pelo menos). Se você quiser inserir texto de justificativa como um comentário genérico, em vez de ser uma justificativa de que a situação é aceitável, inicie o bloco de texto com '//' seguido de um espaço. Feedback é bem-vindo via site do GitHub como questões ou pull requests Há também uma lista de discussão para discussão geral.

Fornecemos com prazer as informações em vários idiomas, no entanto, se houver qualquer conflito ou inconsistência entre as traduções, a versão em inglês é a versão autoritativa.
Se este é o seu projeto, por favor mostre o status do seu selo na página do seu projeto! O status do selo se parece com isto: O nível do selo para o projeto 14430 é in_progress Aqui está como incorporá-lo:
Você pode mostrar o status do seu selo incorporando isto no seu arquivo markdown:
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/14430/badge)](https://www.bestpractices.dev/projects/14430)
ou incorporando isto no seu HTML:
<a href="https://www.bestpractices.dev/projects/14430"><img src="https://www.bestpractices.dev/projects/14430/badge"></a>


Estes são os critérios de nível de Aprovação. Você também pode visualizar os critérios de nível Prata ou Ouro.

Baseline Series: Nível Básico 1 Nível Básico 2 Nível Básico 3

        

 Fundamentos 13/13 ●

  • Geral

    Observe que outros projetos podem usar o mesmo nome.

    Self-hosted artist/composer metadata and image manager for Emby, Jellyfin, and Kodi

    Use o formato de expressão de licença SPDX; exemplos incluem "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "GPL-2.0+", "LGPL-3.0+", "MIT" e "(BSD-2-Clause OR Ruby)". Não inclua aspas simples ou aspas duplas.
    Se houver mais de uma linguagem, liste-as como valores separados por vírgula (espaços opcionais) e ordene-as da mais usada para a menos usada. Se houver uma longa lista, liste pelo menos as três primeiras mais comuns. Se não houver linguagem (por exemplo, este é um projeto apenas de documentação ou apenas de teste), use o caractere único "-". Use uma capitalização convencional para cada linguagem, por exemplo, "JavaScript".
    O Common Platform Enumeration (CPE) é um esquema de nomenclatura estruturado para sistemas de tecnologia da informação, software e pacotes. Ele é usado em vários sistemas e bancos de dados ao relatar vulnerabilidades.
  • Conteúdo básico do site do projeto


    O site do projeto DEVE descrever sucintamente o que o software faz (qual problema ele resolve?). [description_good]
    Isso DEVE estar em linguagem que usuários potenciais possam entender (por exemplo, ele usa o mínimo de jargão).

    The README's opening paragraph states what Stillwater does and the problem it solves, in language aimed at self-hosted media-server users rather than developers: https://github.com/sydlexius/stillwater#readme

    It names the software (a self-hosted web app), what it operates on (artist and composer metadata for a music library), where the results go (artist.nfo files, or pushed to Emby/Jellyfin over their APIs), and the two problems it exists to solve: artists that other tools leave blank, and manual edits being overwritten the next time a server refreshes. The same description appears on the documentation site at https://sydlexius.github.io/stillwater/ and as the repository's one-line summary.



    O site do projeto DEVE fornecer informações sobre como: obter, fornecer feedback (como relatórios de bugs ou melhorias) e contribuir com o software. [interact]

    All three are covered, reachable from the README:

    OBTAIN -- the README's "Quick start" section gives a working docker-compose file, and the documentation site carries full install guides for Docker, prebuilt binaries, Unraid Community Applications, and reverse-proxy setups: https://github.com/sydlexius/stillwater#quick-start and https://sydlexius.github.io/stillwater/

    FEEDBACK -- bug reports and enhancement requests go through GitHub Issues, with three templates (bug, feature, task) offered at https://github.com/sydlexius/stillwater/issues/new/choose . CONTRIBUTING.md documents which template to use and asks that larger ideas start with a short scope sketch in the issue body; questions are directed to the question label.

    CONTRIBUTE -- the README's "Contributing" section links CONTRIBUTING.md, which covers development environment setup, code style, and the pull-request workflow: https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md . Participants are asked to follow the Code of Conduct: https://github.com/sydlexius/stillwater/blob/main/CODE_OF_CONDUCT.md

    Security vulnerabilities are deliberately routed away from public issues to a private disclosure process documented in SECURITY.md.



    As informações sobre como contribuir DEVEM explicar o processo de contribuição (por exemplo, pull requests são usados?) (URL obrigatória) [contribution]
    Presumimos que projetos no GitHub usam issues e pull requests, a menos que indicado de outra forma. Essa informação pode ser breve, por exemplo, declarando que o projeto usa pull requests, um rastreador de issues ou postagens em uma lista de discussão (qual?)

    Non-trivial contribution file in repository: https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md.



    As informações sobre como contribuir DEVERIAM incluir os requisitos para contribuições aceitáveis (por exemplo, uma referência a qualquer padrão de codificação exigido). (URL obrigatória) [contribution_requirements]

    https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md#code-style

    CONTRIBUTING.md's "Code style" section states the requirements for an acceptable contribution and links the enforcing configuration:

    The "Pull request workflow" section adds the process requirements a contribution must satisfy: branch from main (direct commits are refused by branch protection), a conventional-commit prefix on the squash commit, and a passing local pre-push gate before pushing. These are enforced rather than advisory -- every PR must pass required CI checks including tests, a patch-coverage floor, CodeQL, and code review before it can merge.


  • Licença FLOSS


    O software produzido pelo projeto DEVE ser lançado como FLOSS. [floss_license]
    FLOSS é software lançado de uma forma que atende à Definição de Código Aberto ou à Definição de Software Livre. Exemplos de tais licenças incluem CC0, MIT, BSD 2-clause, BSD 3-clause revisada, Apache 2.0, Lesser GNU General Public License (LGPL) e a GNU General Public License (GPL). Para nossos propósitos, isso significa que a licença DEVE ser: O software PODE também ser licenciado de outras formas (por exemplo, "GPLv2 ou proprietário" é aceitável).

    The GPL-3.0 license is approved by the Open Source Initiative (OSI).



    É SUGERIDO que qualquer licença(s) exigida para o software produzido pelo projeto seja aprovada pela Open Source Initiative (OSI). [floss_license_osi]
    A OSI usa um processo de aprovação rigoroso para determinar quais licenças são OSS.

    The GPL-3.0 license is approved by the Open Source Initiative (OSI).



    O projeto DEVE publicar a(s) licença(s) de seus resultados em um local padrão em seu repositório de código-fonte. (URL obrigatória) [license_location]
    Uma convenção é publicar a licença como um arquivo de nível superior chamado LICENSE ou COPYING, que PODE ser seguido por uma extensão como ".txt" ou ".md". Uma convenção alternativa é ter um diretório chamado LICENSES contendo arquivo(s) de licença; esses arquivos são tipicamente nomeados como seu identificador de licença SPDX seguido por uma extensão de arquivo apropriada, conforme descrito na Especificação REUSE. Observe que este critério é apenas um requisito no repositório de código-fonte. Você NÃO precisa incluir o arquivo de licença ao gerar algo a partir do código-fonte (como um executável, pacote ou contêiner). Por exemplo, ao gerar um pacote R para a Comprehensive R Archive Network (CRAN), siga a prática padrão do CRAN: se a licença for uma licença padrão, use a especificação de licença curta padrão (para evitar instalar outra cópia do texto) e liste o arquivo LICENSE em um arquivo de exclusão como .Rbuildignore. Da mesma forma, ao criar um pacote Debian, você pode colocar um link no arquivo de copyright para o texto da licença em /usr/share/common-licenses e excluir o arquivo de licença do pacote criado (por exemplo, deletando o arquivo após chamar dh_auto_install). Nós encorajamos a inclusão de informações de licença legíveis por máquina em formatos gerados, quando praticável.

    Non-trivial license location file in repository: https://github.com/sydlexius/stillwater/blob/main/LICENSE.


  • Documentação


    O projeto DEVE fornecer documentação básica para o software produzido pelo projeto. [documentation_basics]
    Esta documentação deve estar em alguma mídia (como texto ou vídeo) que inclua: como instalá-lo, como iniciá-lo, como usá-lo (possivelmente com um tutorial usando exemplos) e como usá-lo de forma segura (por exemplo, o que fazer e o que não fazer) se esse for um tópico apropriado para o software. A documentação de segurança não precisa ser longa. O projeto PODE usar hiperlinks para material não pertencente ao projeto como documentação. Se o projeto não produz software, escolha "não aplicável" (N/A).

    The documentation site at https://sydlexius.github.io/stillwater/ carries 75 pages covering installation through reference, organized by task:

    GETTING STARTED (8 pages) -- first-run setup walkthrough plus install guides for Docker Compose, prebuilt binary, and Unraid Community Applications, and connection guides for Emby, Jellyfin, and Lidarr: https://sydlexius.github.io/stillwater/getting-started/

    CORE CONCEPTS (10 pages) -- how the software actually behaves: metadata providers and per-field fallback, field locking, image handling, NFO write-back: https://sydlexius.github.io/stillwater/core-concepts/

    HOW-TO (27 pages) -- task-oriented guides for the operations a user actually performs.

    REFERENCE (8 pages) -- the CLI, environment variables, every setting by tab, the rules catalogue, providers, preferences, and UI labels: https://sydlexius.github.io/stillwater/reference/

    TROUBLESHOOTING, plus a documented REST API. The API is additionally covered by an OpenAPI specification and an executable Bruno collection in the repository, and make check-openapi gates the spec against the implementation so it cannot drift silently.

    The README gives the short version -- what the software does, a working docker-compose quick start, and the feature summary -- and links the full site: https://github.com/sydlexius/stillwater#readme

    Several reference pages are GENERATED from the source of truth rather than hand-maintained (the rules catalogue, the settings reference, and the doc anchors), so they cannot drift from the implementation.



    O projeto DEVE fornecer documentação de referência que descreva a interface externa (tanto entrada quanto saída) do software produzido pelo projeto. [documentation_interface]
    A documentação de uma interface externa explica a um usuário final ou desenvolvedor como usá-la. Isso incluiria sua interface de programação de aplicativos (API) se o software tiver uma. Se for uma biblioteca, documente as principais classes/tipos e métodos/funções que podem ser chamados. Se for uma aplicação web, defina sua interface de URL (geralmente sua interface REST). Se for uma interface de linha de comando, documente os parâmetros e opções que suporta. Em muitos casos, é melhor que a maior parte desta documentação seja gerada automaticamente, para que essa documentação permaneça sincronizada com o software conforme ele muda, mas isso não é obrigatório. O projeto PODE usar hiperlinks para material não pertencente ao projeto como documentação. A documentação PODE ser gerada automaticamente (quando praticável, esta é frequentemente a melhor forma de fazê-lo). A documentação de uma interface REST pode ser gerada usando Swagger/OpenAPI. A documentação da interface de código PODE ser gerada usando ferramentas como JSDoc (JavaScript), ESDoc (JavaScript), pydoc (Python), devtools (R), pkgdown (R) e Doxygen (muitos). Simplesmente ter comentários no código de implementação não é suficiente para satisfazer este critério; precisa haver uma maneira fácil de ver a informação sem ler todo o código-fonte. Se o projeto não produz software, escolha "não aplicável" (N/A).

    Every external interface the software exposes is documented, and most of the reference material is generated from the source of truth rather than maintained by hand.

    REST API. The project ships an OpenAPI specification covering 234 paths and 274 operations, describing request and response shapes for the whole /api/v1/ surface: https://github.com/sydlexius/stillwater/blob/main/internal/api/openapi.yaml . The API is documented on the documentation site at https://sydlexius.github.io/stillwater/api/

    The specification is verified against the implementation rather than trusted. make check-openapi compares the spec to the actual handlers, and it runs as a gate -- so a change to a request or response shape that is not reflected in the spec fails rather than silently leaving the documentation wrong. An executable Bruno collection additionally exercises the live API end to end in CI, which is a second, behavioural check that the documented interface is the one the server actually serves.

    COMMAND-LINE INTERFACE. Documented at https://sydlexius.github.io/stillwater/reference/cli/ , covering the flags and subcommands, including the operational one-shot passes (for example the pre-guard lock-damage dry-run and repair, with their approval-digest arguments).

    CONFIGURATION INTERFACE. Environment variables are documented at https://sydlexius.github.io/stillwater/reference/environment-variables/ , and every user-facing setting is catalogued by tab at https://sydlexius.github.io/stillwater/reference/settings-by-tab/ . The settings reference and the rules catalogue are GENERATED from the code that defines them, so they cannot drift from the implementation; a documentation-drift check runs in CI and fails when a shipped page no longer matches the code it describes.

    OTHER SURFACES. The provider set and their per-field behaviour are documented at https://sydlexius.github.io/stillwater/reference/providers/ , user preferences at .../reference/preferences/ , and UI labels at .../reference/ui-labels/ . The reference section runs to 8 pages, within a documentation site of 75 pages total.

    Interface documentation is therefore readable without opening the source, which is what this criterion asks: a consumer can learn the REST API, the CLI, and the configuration surface entirely from published pages.


  • Outro


    Os sites do projeto (site, repositório e URLs de download) DEVEM suportar HTTPS usando TLS. [sites_https]
    Isso requer que a URL da página inicial do projeto e a URL do repositório de controle de versão comecem com "https:", não "http:". Você pode obter certificados gratuitos do Let's Encrypt. Os projetos PODEM implementar este critério usando (por exemplo) GitHub pages, GitLab pages ou SourceForge project pages. Se você suportar HTTP, recomendamos que você redirecione o tráfego HTTP para HTTPS.

    All three project URLs are HTTPS, verified live.

    Repository: https://github.com/sydlexius/stillwater -- 200 over TLS.

    Documentation site: https://sydlexius.github.io/stillwater/ -- 200 over TLS, served by GitHub Pages with its GitHub-managed certificate. Plain HTTP is not merely supported, it redirects: http://sydlexius.github.io/stillwater/ returns 301 to the HTTPS URL.

    Downloads: releases are served from GitHub over HTTPS at https://github.com/sydlexius/stillwater/releases , and container images from GitHub Container Registry (ghcr.io) over HTTPS. Release artifacts are additionally signed with Sigstore, so their provenance is verifiable independently of the transport.



    O projeto DEVE ter um ou mais mecanismos para discussão (incluindo mudanças propostas e questões) que sejam pesquisáveis, permitam que mensagens e tópicos sejam endereçados por URL, permitam que novas pessoas participem de algumas das discussões e não exijam instalação no lado do cliente de software proprietário. [discussion]
    Exemplos de mecanismos aceitáveis incluem lista(s) de discussão arquivadas, discussões de questões e pull requests do GitHub, Bugzilla, Mantis e Trac. Mecanismos de discussão assíncronos (como IRC) são aceitáveis se atenderem a esses critérios; certifique-se de que haja um mecanismo de arquivamento endereçável por URL. JavaScript proprietário, embora desencorajado, é permitido.

    GitHub supports discussions on issues and pull requests.



    O projeto DEVERIA fornecer documentação em inglês e ser capaz de aceitar relatórios de bugs e comentários sobre código em inglês. [english]
    O inglês é atualmente a língua franca da tecnologia de computadores; o suporte ao inglês aumenta o número de diferentes desenvolvedores e revisores em potencial em todo o mundo. Um projeto pode atender a este critério mesmo que o idioma principal de seus desenvolvedores principais não seja o inglês.

    The project is developed and documented entirely in English. The README, CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md, the full documentation site at https://sydlexius.github.io/stillwater/ , all in-repo design and reference docs, the three GitHub issue templates, code comments, and commit messages are all written in English. Issues, pull request discussion, and code review are conducted in English: https://github.com/sydlexius/stillwater/issues and https://github.com/sydlexius/stillwater/pulls. The application's own user interface is written in US English.



    O projeto DEVE ser mantido. [maintained]
    No mínimo, o projeto deve tentar responder a relatórios significativos de problemas e vulnerabilidades. Um projeto que está buscando ativamente um badge provavelmente é mantido. Todos os projetos e pessoas têm recursos limitados, e projetos típicos devem rejeitar algumas mudanças propostas, portanto, recursos limitados e rejeições de propostas não indicam por si só um projeto não mantido.

    Quando um projeto souber que não será mais mantido, ele deve definir este critério como "Não atendido" e usar o(s) mecanismo(s) apropriado(s) para indicar a outros que não está sendo mantido. Por exemplo, use "DEPRECATED" como o primeiro cabeçalho de seu README, adicione "DEPRECATED" perto do início de sua página inicial, adicione "DEPRECATED" ao início da descrição do projeto do repositório de código, adicione um badge de sem intenção de manutenção em seu README e/ou página inicial, marque-o como descontinuado em quaisquer repositórios de pacotes (por exemplo, npm deprecate), e/ou use o sistema de marcação do repositório de código para arquivá-lo (por exemplo, a configuração "archive" do GitHub, a marcação "archived" do GitLab, o status "readonly" do Gerrit ou o status de projeto "abandoned" do SourceForge). Discussão adicional pode ser encontrada aqui.

    The project is under active development, with the most recent commit today.

    COMMITS: 648 in the last 90 days, the latest on 2026-09-02.

    RELEASES: four stable releases in the past month -- v1.6.1 (2026-08-04), v1.6.2 (08-19), v1.6.3 (08-22), v1.6.4 (08-27) -- plus automated nightly pre-releases, the most recent on 2026-09-02. Release artifacts are signed with Sigstore.

    ISSUE ACTIVITY: 94 issues closed in the last 30 days, against 295 open. The open count reflects a tracked and milestoned backlog rather than neglect: issues are filed with a milestone and labels at creation, work is scheduled through release milestones, and defects found during review are captured as tracked issues rather than dropped.

    REVIEW AND CI: every change lands through a pull request with required CI checks (tests, a patch-coverage floor, CodeQL, lint, and a generated-file drift check) and required code review; direct commits to the default branch are refused by branch protection. Dependabot is configured for dependency updates.

    Repository activity is visible at https://github.com/sydlexius/stillwater/commits/main and https://github.com/sydlexius/stillwater/releases


 Controle de Mudanças 9/9 ●

  • Repositório de código-fonte público controlado por versão


    O projeto DEVE ter um repositório de código-fonte controlado por versão que seja publicamente legível e tenha uma URL. [repo_public]
    A URL PODE ser a mesma que a URL do projeto. O projeto PODE usar branches privados (não públicos) em casos específicos enquanto a mudança não for lançada publicamente (por exemplo, para corrigir uma vulnerabilidade antes de ser revelada ao público).

    Repository on GitHub, which provides public git repositories with URLs.



    O repositório de código-fonte do projeto DEVE rastrear quais mudanças foram feitas, quem fez as mudanças e quando as mudanças foram feitas. [repo_track]

    Repository on GitHub, which uses git. git can track the changes, who made them, and when they were made.



    Para permitir revisão colaborativa, o repositório de código-fonte do projeto DEVE incluir versões intermediárias para revisão entre lançamentos; ele NÃO DEVE incluir apenas lançamentos finais. [repo_interim]
    Os projetos PODEM optar por omitir versões intermediárias específicas de seus repositórios de código-fonte públicos (por exemplo, aquelas que corrigem vulnerabilidades de segurança não públicas específicas, podem nunca ser lançadas publicamente ou incluem material que não pode ser legalmente postado e não estão no lançamento final).

    Met. The repository is the live development history, not a release drop.

    https://github.com/sydlexius/stillwater/commits/main -- 648 commits in the last 90 days, 160 merges to the default branch in the last 30 days alone, against four stable releases in that period. Every intermediate state between releases is public.

    Development happens in the open through pull requests, each reviewable before it lands: https://github.com/sydlexius/stillwater/pulls . Direct commits to the default branch are refused by branch protection, so no change reaches main without an interim reviewable state existing first. Review comments and their resolutions stay attached to the PR after merge.

    Automated nightly pre-releases are additionally published from the current development head, so an interim build is available to testers between stable releases: https://github.com/sydlexius/stillwater/releases

    Work in progress is also visible before any code exists, as milestoned and labelled issues: https://github.com/sydlexius/stillwater/issues



    É SUGERIDO que software de controle de versão distribuído comum seja usado (por exemplo, git) para o repositório de código-fonte do projeto. [repo_distributed]
    O Git não é especificamente exigido e os projetos podem usar software de controle de versão centralizado (como subversion) com justificativa.

    Repository on GitHub, which uses git. git is distributed.


  • Numeração de versão única


    Os resultados do projeto DEVEM ter um identificador de versão único para cada lançamento destinado a ser usado pelos usuários. [version_unique]
    Isso PODE ser atendido de várias maneiras, incluindo IDs de commit (como git commit id ou mercurial changeset id) ou um número de versão (incluindo números de versão que usam versionamento semântico ou esquemas baseados em data como AAAAMMDD).

    Met. Every release carries a unique semantic-version identifier.

    Stable releases are tagged vMAJOR.MINOR.PATCH -- v1.6.4 (2026-08-27), v1.6.3 (08-22), v1.6.2 (08-19), v1.6.1 (08-04): https://github.com/sydlexius/stillwater/releases

    Automated nightly builds are separately and unambiguously identified as nightly-YYYYMMDD and are marked as pre-releases, so they cannot be confused with a stable version.

    The identifier is not only a tag. It is compiled into the binary at build time via linker flags -- internal/version.Version, alongside the exact commit SHA and build date -- so a user can determine precisely which build they are running rather than inferring it from a filename. A CI guard in the release workflow specifically checks that the ldflags symbol path has not silently drifted, since a renamed package would otherwise leave the version unset without failing the build.

    Container images are tagged with the same version identifiers on GitHub Container Registry, and release artifacts are signed with Sigstore, so a given version is verifiable as well as identifiable.



    É SUGERIDO que o formato de numeração de versão Versionamento Semântico (SemVer) ou Versionamento de Calendário (CalVer) seja usado para lançamentos. É SUGERIDO que aqueles que usam CalVer incluam um valor de nível micro. [version_semver]
    Os projetos geralmente devem preferir qualquer formato que seja esperado por seus usuários, por exemplo, porque é o formato normal usado por seu ecossistema. Muitos ecossistemas preferem SemVer, e SemVer é geralmente preferido para interfaces de programação de aplicações (APIs) e kits de desenvolvimento de software (SDKs). CalVer tende a ser usado por projetos que são grandes, têm um número excepcionalmente grande de dependências desenvolvidas independentemente, têm um escopo em constante mudança ou são sensíveis ao tempo. É SUGERIDO que aqueles que usam CalVer incluam um valor de nível micro, porque incluir um nível micro suporta branches mantidos simultaneamente sempre que isso se tornar necessário. Outros formatos de numeração de versão podem ser usados como números de versão, incluindo IDs de commit do git ou IDs de changeset do mercurial, desde que identifiquem exclusivamente as versões. No entanto, algumas alternativas (como IDs de commit do git) podem causar problemas como identificadores de lançamento, porque os usuários podem não ser capazes de determinar facilmente se estão atualizados. O formato do ID de versão pode não ser importante para identificar lançamentos de software se todos os destinatários executarem apenas a versão mais recente (por exemplo, é o código para um único site ou serviço de internet que é constantemente atualizado via entrega contínua).


    É SUGERIDO que os projetos identifiquem cada lançamento dentro de seu sistema de controle de versão. Por exemplo, é SUGERIDO que aqueles que usam git identifiquem cada lançamento usando tags do git. [version_tags]

    Met. Every release is identified by a git tag in the repository: https://github.com/sydlexius/stillwater/tags

    62 version tags are present, following vMAJOR.MINOR.PATCH -- for example v1.6.4, v1.6.3, v1.6.2, v1.6.1 -- with release-candidate tags (v1.6.0-rc0, v1.6.0-rc1) where a release was staged. The tags are ANNOTATED rather than lightweight, so each carries its own tagger and date.

    Nightly pre-release builds are tagged separately as nightly-YYYYMMDD, keeping them distinguishable from stable releases in the tag list as well as on the releases page.

    Each tag is what drives the release: the release workflow builds from the tag and stamps that same identifier into the binary via linker flags, so a tag, a GitHub release, and the version a running binary reports all refer to the same commit.


  • Notas de lançamento


    O projeto DEVE fornecer, em cada lançamento, notas de lançamento que sejam um resumo legível por humanos das principais mudanças nesse lançamento para ajudar os usuários a determinar se devem atualizar e qual será o impacto da atualização. As notas de lançamento NÃO DEVEM ser a saída bruta de um log de controle de versão (por exemplo, os resultados do comando "git log" não são notas de lançamento). Projetos cujos resultados não se destinam à reutilização em vários locais (como o software para um único site ou serviço) E empregam entrega contínua PODEM selecionar "N/A". (URL obrigatória) [release_notes]
    As notas de lançamento PODEM ser implementadas de várias maneiras. Muitos projetos as fornecem em um arquivo chamado "NEWS", "CHANGELOG" ou "ChangeLog", opcionalmente com extensões como ".txt", ".md" ou ".html". Historicamente, o termo "change log" significava um log de todas as mudanças, mas para atender a esses critérios, o que é necessário é um resumo legível por humanos. As notas de lançamento PODEM, em vez disso, ser fornecidas por mecanismos de sistema de controle de versão, como o fluxo de trabalho GitHub Releases.

    https://github.com/sydlexius/stillwater/releases

    Every release ships hand-written release notes, structured as a plain-language summary of what changed and what it means for the user -- not a git log dump.

    The most recent, v1.6.4 (https://github.com/sydlexius/stillwater/releases/tag/v1.6.4), is representative. It opens with a one-sentence statement of what the release delivers, then a Highlights section explaining each significant change in terms of the user-visible symptom rather than the code: what went wrong, what it caused, and what now happens instead. Issue numbers are cited so a reader can follow any item to its full history.

    Upgrade impact is addressed directly where it exists. v1.6.4 shipped a repair for damage caused before an earlier guard existed, so the notes carry a dedicated section explaining that the repair is a deliberate one-time pass rather than something that runs at startup, instructing the user to stop the server and back up the database first, giving the exact commands for the dry-run preview and the approved repair, and explaining why the preview requires human judgment that no automatic test can substitute for.

    Earlier releases follow the same structure: v1.6.3, v1.6.2, v1.6.1. The project ships small, frequent, semver-correct releases, which keeps each set of notes specific enough to be read rather than skimmed.



    As notas de lançamento DEVEM identificar todas as vulnerabilidades de tempo de execução publicamente conhecidas corrigidas neste lançamento que já tinham uma atribuição CVE ou similar quando o lançamento foi criado. Este critério pode ser marcado como não aplicável (N/A) se os usuários normalmente não conseguem atualizar o software por conta própria (por exemplo, como geralmente é verdade para atualizações de kernel). Este critério se aplica apenas aos resultados do projeto, não às suas dependências. Se não houver notas de lançamento ou se não houve vulnerabilidades publicamente conhecidas, escolha N/A. [release_notes_vulns]
    Este critério ajuda os usuários a determinar se uma determinada atualização irá corrigir uma vulnerabilidade que é publicamente conhecida, para ajudar os usuários a tomar uma decisão informada sobre atualização. Se os usuários normalmente não conseguem atualizar o software por conta própria em seus computadores, mas devem depender de um ou mais intermediários para realizar a atualização (como é frequentemente o caso de um kernel e software de baixo nível que está entrelaçado com um kernel), o projeto pode escolher "não aplicável" (N/A) em vez disso, já que essa informação adicional não será útil para esses usuários. Da mesma forma, um projeto pode escolher N/A se todos os destinatários executarem apenas a versão mais recente (por exemplo, é o código para um único site ou serviço de internet que é constantemente atualizado via entrega contínua). Este critério se aplica apenas aos resultados do projeto, não às suas dependências. Listar as vulnerabilidades de todas as dependências transitivas de um projeto torna-se difícil conforme as dependências aumentam e variam, e é desnecessário já que ferramentas que examinam e rastreiam dependências podem fazer isso de uma forma mais escalável.

    N/A -- there have been no publicly known vulnerabilities in Stillwater itself.

    No CVE has been assigned against this project. Verified against NIST's CPE dictionary: neither the product nor the vendor name returns any entry, which is expected for a project with no published CVE. The repository has published zero GitHub security advisories: https://github.com/sydlexius/stillwater/security/advisories

    The criterion applies to the project's own results rather than its dependencies. Dependency advisories are handled separately and continuously -- Dependabot is configured, govulncheck runs in CI, and CodeQL scans every pull request -- but none of those are vulnerabilities in Stillwater's own code.

    A private disclosure process is in place for when one does arise, documented in SECURITY.md: https://github.com/sydlexius/stillwater/blob/main/SECURITY.md . Release notes are hand-written per release and would carry such a fix.


 Relatórios 8/8 ●

  • Processo de relato de bugs


    O projeto DEVE fornecer um processo para os usuários enviarem relatórios de bugs (por exemplo, usando um rastreador de problemas ou uma lista de discussão). (URL obrigatória) [report_process]

    Non-trivial SECURITY[.md] file found file in repository: https://github.com/sydlexius/stillwater/blob/main/SECURITY.md. [osps_do_02_01]



    O projeto DEVERIA usar um rastreador de problemas para rastrear problemas individuais. [report_tracker]

    Met. The project uses GitHub Issues: https://github.com/sydlexius/stillwater/issues

    It is used as a working tracker rather than an inbox. Three issue templates route reports to the right shape (bug, feature, task): https://github.com/sydlexius/stillwater/issues/new/choose

    Issues are triaged at creation: every issue is assigned a milestone and labels when it is filed, drawn from 24 milestones and a 45-label taxonomy covering type (bug, enhancement, chore, technical-debt), scope, and affected area (images, rules, ui, providers, database, and so on). An unmilestoned issue does not appear in any release view, so the convention exists to keep work schedulable rather than invisible.

    Recent throughput: 94 issues closed in the last 30 days. Defects surfaced during code review are captured as tracked issues with the milestone of the work that surfaced them, rather than dropped or left in a comment thread.

    Security vulnerabilities are deliberately routed away from the public tracker to a private disclosure process: https://github.com/sydlexius/stillwater/blob/main/SECURITY.md



    O projeto DEVE reconhecer a maioria dos relatórios de bugs enviados nos últimos 2-12 meses (inclusive); a resposta não precisa incluir uma correção. [report_responses]

    Met. Every bug report is triaged, and the great majority are resolved.

    Of the 400 issues labelled bug filed in the last 12 months, 394 carry a milestone -- 98.5%. Assigning a milestone and labels at filing time is the project's convention, and it is the acknowledgement: it places the report in a release view where it can be scheduled, rather than leaving it unrouted. The 6 without one are a rounding error, not a backlog of ignored reports.

    Resolution rate is high as well: two thirds of the bug reports in that window are already closed, and 94 issues of all types were closed in the last 30 days alone.

    Reports are also acted on rather than merely filed. Defects surfaced during code review are captured as tracked issues carrying the milestone of the work that surfaced them, and issues frequently accumulate investigation comments -- measurement results, refuted hypotheses, design decisions -- before any code is written.

    The tracker is public: https://github.com/sydlexius/stillwater/issues



    O projeto DEVERIA responder a uma maioria (>50%) das solicitações de melhorias nos últimos 2-12 meses (inclusive). [enhancement_responses]
    A resposta PODE ser 'não' ou uma discussão sobre seus méritos. O objetivo é simplesmente que haja alguma resposta a algumas solicitações, o que indica que o projeto ainda está ativo. Para fins deste critério, os projetos não precisam contar solicitações falsas (por exemplo, de spammers ou sistemas automatizados). Se um projeto não estiver mais fazendo melhorias, selecione "não atendido" e inclua a URL que torna esta situação clara para os usuários. Se um projeto tende a ser sobrecarregado pelo número de solicitações de melhorias, selecione "não atendido" e explique.

    Met. Of the 400 issues labelled enhancement filed in the last 12 months, 391 carry a milestone -- 97.75% -- and 231 are already closed, so well over half have been both responded to and resolved.

    Enhancement requests are triaged at filing: a milestone and labels are assigned when the issue is created, which places the request in a release view where it can be scheduled or explicitly deferred, rather than left unrouted. An unmilestoned issue appears in no release view, so the convention exists precisely to keep proposals from going silently unanswered.

    The feature template asks that larger ideas open with a short scope sketch in the issue body so the design can be discussed before any code is written, and CONTRIBUTING.md directs contributors to raise a feature that way rather than starting with a pull request: https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md#suggesting-a-feature

    Proposals that are declined or reshaped are answered in the issue with the reasoning, and larger ones are decomposed into epics with tracked children rather than closed as too big.

    Tracker: https://github.com/sydlexius/stillwater/issues?q=is%3Aissue+label%3Aenhancement



    O projeto DEVE ter um arquivo publicamente disponível para relatórios e respostas para pesquisa posterior. (URL obrigatória) [report_archive]

    https://github.com/sydlexius/stillwater/issues?q=is%%3Aissue

    All bug reports, enhancement requests, and their responses are permanently archived in the public GitHub issue tracker, open and closed alike, and are full-text searchable without an account. Closed issues are never deleted, so the reasoning behind a decision remains readable long after the work ships.

    Pull request discussion is archived alongside it and is equally searchable: https://github.com/sydlexius/stillwater/pulls?q=is%%3Apr . Review comments and their resolutions stay attached to the pull request after merge, so the argument that produced a change is recoverable from the change itself.

    The two are cross-linked in both directions -- pull requests reference the issues they address, and merged work appears in the issue's timeline -- so a search that lands on either finds the other.

    Releases carry hand-written notes citing the issue numbers they resolve, giving a third searchable path from a shipped version back to the discussion behind it: https://github.com/sydlexius/stillwater/releases


  • Processo de relato de vulnerabilidades


    O projeto DEVE publicar o processo para relatar vulnerabilidades no site do projeto. (URL obrigatória) [vulnerability_report_process]
    Projetos hospedados no GitHub DEVERIAM considerar habilitar o relato privado de uma vulnerabilidade de segurança. Projetos no GitLab DEVERIAM considerar usar sua capacidade de relatar uma vulnerabilidade de forma privada. Projetos PODEM identificar um endereço de e-mail em https://PROJECTSITE/security, frequentemente na forma security@example.org. Este processo de relato de vulnerabilidades PODE ser o mesmo que seu processo de relato de bugs. Relatórios de vulnerabilidades PODEM ser sempre públicos, mas muitos projetos têm um mecanismo de relato de vulnerabilidades privado.

    https://github.com/sydlexius/stillwater/blob/main/SECURITY.md

    SECURITY.md publishes the full reporting process, and GitHub surfaces it automatically in the repository's Security tab and on the "Report a vulnerability" flow.

    The policy states plainly that vulnerabilities must NOT be reported through public GitHub issues, and directs reporters to a private channel -- GitHub Security Advisories: https://github.com/sydlexius/stillwater/security/advisories/new -- so an issue can be triaged and a fix prepared before public disclosure.

    It specifies what a report should contain: a description of the vulnerability and its impact, steps to reproduce or a proof of concept, the affected versions, and a suggested fix if the reporter has one.

    It sets expectations both ways. An initial acknowledgement is promised within 72 hours of receipt; once confirmed, a fix is developed and released as soon as practical, typically within 14 days for critical issues.

    It also defines scope explicitly, which keeps a reporter from spending effort on something that will be declined. In scope: the application binary and Docker image, the REST API, authentication and session management, encryption of stored secrets, and file system operations. Out of scope: upstream dependency vulnerabilities (directed to the upstream project), issues requiring physical host access, and denial of service through expected resource usage.

    Supported versions are stated as well -- only the latest release receives security updates.



    Se relatórios privados de vulnerabilidades forem suportados, o projeto DEVE incluir como enviar as informações de uma forma que seja mantida privada. (URL obrigatória) [vulnerability_report_private]
    Exemplos incluem um relatório de defeito privado enviado na web usando HTTPS (TLS) ou um e-mail criptografado usando OpenPGP. Se relatórios de vulnerabilidades forem sempre públicos (portanto, nunca há relatórios privados de vulnerabilidades), escolha "não aplicável" (N/A).

    https://github.com/sydlexius/stillwater/security/advisories/new

    Yes, private reporting is supported and is the required channel. SECURITY.md (https://github.com/sydlexius/stillwater/blob/main/SECURITY.md) states that vulnerabilities must NOT be reported through public GitHub issues, and directs reporters to GitHub Security Advisories at the URL above.

    That channel is private by construction: a draft advisory is visible only to the reporter and the repository maintainers until it is deliberately published, so the report, the discussion, and any proof-of-concept stay confidential while a fix is prepared. It requires no email exchange and no key management by the reporter, and it is reachable from the repository's Security tab as well as from the link in SECURITY.md.

    The policy also tells a reporter what to expect after sending: an initial acknowledgement within 72 hours, and a fix released as soon as practical -- typically within 14 days for critical issues -- before public disclosure.



    O tempo de resposta inicial do projeto para qualquer relatório de vulnerabilidade recebido nos últimos 6 meses DEVE ser menor ou igual a 14 dias. [vulnerability_report_response]
    Se não houve vulnerabilidades relatadas nos últimos 6 meses, escolha "não aplicável" (N/A).

    N/A -- no vulnerability reports have been received in the last 6 months, or at any point.

    The repository has published zero security advisories (https://github.com/sydlexius/stillwater/security/advisories) and no CVE has been assigned against the project, so there is no response time to measure.

    The commitment is published in advance for when one does arrive: SECURITY.md promises an initial acknowledgement within 72 hours of receipt -- well inside the 14-day bar -- with a fix released as soon as practical, typically within 14 days for critical issues. https://github.com/sydlexius/stillwater/blob/main/SECURITY.md

    Reports arrive through GitHub Security Advisories, which notifies maintainers directly rather than relying on a monitored mailbox: https://github.com/sydlexius/stillwater/security/advisories/new


 Qualidade 13/13 ●

  • Sistema de compilação funcional


    Se o software produzido pelo projeto requer construção para uso, o projeto DEVE fornecer um sistema de construção funcional que possa reconstruir automaticamente o software a partir do código-fonte. [build]
    Um sistema de construção determina quais ações precisam ocorrer para reconstruir o software (e em que ordem), e então executa essas etapas. Por exemplo, ele pode invocar um compilador para compilar o código-fonte. Se um executável é criado a partir do código-fonte, deve ser possível modificar o código-fonte do projeto e então gerar um executável atualizado com essas modificações. Se o software produzido pelo projeto depende de bibliotecas externas, o sistema de construção não precisa construir essas bibliotecas externas. Se não houver necessidade de construir nada para usar o software depois que seu código-fonte for modificado, selecione "não aplicável" (N/A).

    The project builds from source with a single command.

    make build compiles the binary, and it is not a bare go build -- it depends on the templ and tailwind targets, so generated Go template code and the compiled stylesheet are regenerated first and cannot silently fall out of date with their sources. The Makefile documents 37 targets, discoverable via make help: https://github.com/sydlexius/stillwater/blob/main/Makefile

    Version information is injected at build time through linker flags (version, commit SHA, build date), so a binary reports exactly which source it came from.

    Container builds are equally reproducible from source: https://github.com/sydlexius/stillwater/tree/main/build/docker

    The build is verified continuously rather than assumed to work. Every pull request runs the full build in CI on a clean runner, and a required generated-file drift check fails the build if committed generated output does not match what regenerating from source produces -- so "it builds on the maintainer's machine" is not sufficient to merge. The release workflow builds the shipped artifacts from the tagged source in CI, and it carries its own guard against the version-injection symbol path drifting silently.

    Build prerequisites and the local development workflow are documented at https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md#development-environment



    É SUGERIDO que ferramentas comuns sejam usadas para construir o software. [build_common_tools]
    Por exemplo, Maven, Ant, cmake, o autotools, make, rake (Ruby) ou devtools (R).

    Non-trivial build file in repository: https://github.com/sydlexius/stillwater/blob/main/Makefile.



    O projeto DEVERIA ser construível usando apenas ferramentas FLOSS. [build_floss_tools]

    Every tool required to build Stillwater from source is FLOSS.

    • Go toolchain (Go 1.27) -- BSD-3-Clause
    • templ (github.com/a-h/templ), the HTML templating generator -- MIT. Invoked as go tool templ, so it is pinned as a module dependency rather than an ambient install.
    • Tailwind CSS, for the stylesheet build -- MIT
    • Node.js, which Tailwind runs under -- MIT
    • GNU Make, driving the build -- GPL
    • git -- GPL-2.0
    • Docker or any OCI-compatible builder for container images; the Dockerfiles are plain and buildable with Podman or Buildah as well: https://github.com/sydlexius/stillwater/tree/main/build/docker

    No proprietary compiler, SDK, IDE, or paid service is needed at any point. A contributor on Linux, macOS, or Windows can clone the repository and run make build with nothing but the above.

    Development and CI tooling is FLOSS as well -- golangci-lint (GPL-3.0), govulncheck (BSD-3-Clause), and Go's built-in test and fuzz tooling. The CI workflows run on GitHub-hosted runners, but nothing in the build depends on GitHub specifically: the same Makefile targets CI invokes are the ones a contributor runs locally.

    Build prerequisites are documented at https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md#development-environment


  • Conjunto de testes automatizados


    O projeto DEVE usar pelo menos um conjunto de testes automatizados que seja disponibilizado publicamente como FLOSS (esse conjunto de testes pode ser mantido como um projeto FLOSS separado). O projeto DEVE mostrar ou documentar claramente como executar o(s) conjunto(s) de testes (por exemplo, por meio de um script de integração contínua (CI) ou por meio de documentação em arquivos como BUILD.md, README.md ou CONTRIBUTING.md). [test]
    O projeto PODE usar múltiplos conjuntos de testes automatizados (por exemplo, um que executa rapidamente, versus outro que é mais completo mas requer equipamento especial). Existem muitos frameworks de teste e sistemas de suporte a testes disponíveis, incluindo Selenium (automação de navegador web), Junit (JVM, Java), RUnit (R), testthat (R).

    The project has multiple automated test suites, all built on FLOSS tooling, and how to run them is documented.

    HOW TO RUN -- CONTRIBUTING.md's "Running tests" section: https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md#running-tests

    go test -race ./...
    # or, equivalent
    make test
    

    THE SUITES:

    • Go unit and integration tests -- 754 test files across the module, using Go's standard testing package (BSD-3-Clause). Integration tests run against a real SQLite database via modernc.org/sqlite, not a mock.
    • Native Go fuzzing across roughly 15 packages, with a CI-enforced matrix so a new fuzz target cannot be added without being exercised.
    • Accessibility tests -- Playwright (Apache-2.0) driving axe-core (MPL-2.0) against both Chromium and Firefox.
    • API tests -- an executable Bruno collection (MIT), exercised end to end by make bruno-ci, which builds the binary, starts an ephemeral server, and runs the collection against it.
    • Responsive-layout and load test suites under the same tests/ tree.

    Every suite is FLOSS and none requires a paid service.

    The suites are RUN, not merely present. Every pull request runs them in CI as required status checks, so a change cannot land while they fail: https://github.com/sydlexius/stillwater/blob/main/.github/workflows/ci.yml -- and a patch-coverage floor is itself a required check, so new code arriving without tests fails the build rather than slipping through quietly.



    Um conjunto de testes DEVERIA ser invocável de forma padrão para aquela linguagem. [test_invocation]
    Por exemplo, "make check", "mvn test", ou "rake test" (Ruby).

    The test suite is invoked the standard way for Go:

    go test ./...
    

    with the race detector, which is how this project runs it:

    go test -race ./...
    

    No wrapper, no bespoke runner, no environment fixture required -- a contributor who knows Go needs no project-specific knowledge to run the tests. make test is provided as a convenience alias for exactly that command, not as a substitute for it, and CONTRIBUTING.md presents the two as equivalent: https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md#running-tests

    The auxiliary suites follow their own ecosystems' conventions in the same way -- Go's built-in fuzzing via go test -fuzz, Playwright through its standard runner, and the Bruno API collection through the Bruno CLI. Each is wrapped in a named Makefile target for discoverability (make help lists them), but every one remains runnable directly with its native command.



    É SUGERIDO que o conjunto de testes cubra a maioria (ou idealmente todos) os ramos de código, campos de entrada e funcionalidade. [test_most]

    Coverage is enforced rather than aspirational, at two levels.

    PER-PACKAGE FLOORS. 54 packages carry an individual coverage floor, checked as a required CI status. Floors range from 58% to 100%, with 31 packages at 80% or above; the exact figures are committed at https://github.com/sydlexius/stillwater/blob/main/testdata/coverage-floor.json and mirrored in https://github.com/sydlexius/stillwater/blob/main/codecov.yml so each package is an independent check. A package that regresses below its own floor fails, so coverage cannot quietly erode in one corner while the overall number holds steady.

    PATCH COVERAGE. New and changed code must reach 78%, as a required check. This is the load-bearing one: it means a change arriving without tests fails the build rather than merging and diluting the average later.

    BEYOND LINE COVERAGE. The project treats line coverage as necessary but not sufficient, and tests for behaviour rather than for the metric:

    • Native Go fuzzing across roughly 15 packages exercises input fields with generated input, and a CI-enforced matrix means a fuzz target cannot be added without being run.
    • New tests guarding a bug fix are required to be shown failing without the fix -- revert it, confirm red, restore, confirm green -- so a test that guards nothing is caught before it lands.
    • Accessibility tests run real axe-core through Playwright against both Chromium and Firefox, against a live page rather than static analysis.
    • An executable Bruno collection exercises the REST API end to end against a real server started for the run.
    • Integration tests use a real SQLite database rather than mocks.

    754 test files across the module: https://github.com/sydlexius/stillwater/blob/main/.github/workflows/ci.yml



    É SUGERIDO que o projeto implemente integração contínua (onde código novo ou alterado é frequentemente integrado em um repositório de código central e testes automatizados são executados no resultado). [test_continuous_integration]

    The project runs continuous integration on GitHub Actions, across 22 workflows: https://github.com/sydlexius/stillwater/tree/main/.github/workflows

    FREQUENT INTEGRATION. 648 commits in the last 90 days and 160 merges to the default branch in the last 30, against four stable releases in that period. Every change lands through a pull request; direct commits to the default branch are refused by branch protection, so nothing reaches the trunk without passing through CI first.

    TESTS RUN ON EVERY CHANGE, AND BLOCK. The main workflow (ci.yml) runs the full Go suite with the race detector, lint, a whole-module build, and a generated-file drift check that fails if committed generated output does not match a fresh regeneration. These are required status checks, so a red result stops the change rather than merely reporting.

    SPECIALIZED WORKFLOWS beyond the main suite:

    • bruno-ci.yml -- builds the binary, starts an ephemeral server, and runs the REST API collection against it
    • fuzz.yml -- native Go fuzzing, with a matrix check so a new fuzz target cannot be added without being run
    • codeql.yml -- static analysis on every pull request
    • mutation.yml -- mutation testing, to check the tests themselves have teeth
    • gate.yml -- provider-failure smoke tests and gate-invariant enforcement
    • docs-drift.yml -- fails when the documentation no longer matches the code it describes
    • scorecard.yml -- OpenSSF Scorecard on a schedule
    • nightly.yml / release-nightly.yml -- a nightly build published as a pre-release, so an interim artifact exists between stable releases

    A patch-coverage floor is itself a required check, so new code arriving without tests fails rather than landing quietly. All GitHub Actions are pinned to commit SHAs rather than floating tags, and workflow tokens follow least privilege -- both verified independently by OpenSSF Scorecard, which scores this project 10/10 on CI-Tests, Token-Permissions, and Dangerous-Workflow: https://securityscorecards.dev/viewer/?uri=github.com/sydlexius/stillwater


  • Teste de novas funcionalidades


    O projeto DEVE ter uma política geral (formal ou não) de que conforme nova funcionalidade importante seja adicionada ao software produzido pelo projeto, testes dessa funcionalidade devem ser adicionados a um conjunto de testes automatizados. [test_policy]
    Desde que haja uma política, mesmo que verbal, que diga que desenvolvedores devem adicionar testes ao conjunto de testes automatizados para novas funcionalidades importantes, selecione "Met".

    Met, and the policy is mechanically enforced rather than left to discipline.

    THE POLICY. New and changed code must reach 78% patch coverage. This is a REQUIRED status check, so a change that adds functionality without tests fails and cannot land -- the policy is not an intention a reviewer has to remember to raise. Configuration: https://github.com/sydlexius/stillwater/blob/main/codecov.yml

    Per-package floors back it up: 54 packages each carry their own committed minimum, checked independently, so coverage cannot erode in one area while the overall figure holds steady. https://github.com/sydlexius/stillwater/blob/main/testdata/coverage-floor.json

    WHAT THE POLICY ASKS FOR BEYOND A NUMBER. The project treats coverage as necessary but not sufficient, and documents that in its contributor guidance:

    • A test written for a bug fix must be shown to FAIL without the fix -- revert it, confirm red, restore, confirm green -- so a test that guards nothing is caught before it lands rather than providing false assurance.
    • Tests must assert their own preconditions, so a fixture that silently stops exercising the intended path fails instead of passing vacuously.
    • Tests must not depend on the developer's environment; a dependency on an external tool must be stubbed, because a green local run does not prove a test will pass on a bare CI runner.
    • Concurrent code is tested under the race detector.
    • Mutation testing runs in CI against the test suite itself, checking that the tests actually detect changed behaviour.

    Contributor-facing documentation: https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md and the per-package testing guidance in https://github.com/sydlexius/stillwater/tree/main/.github/instructions

    The result is visible in the history: 754 test files across the module, and features routinely ship in the same pull request as the tests that exercise them.



    O projeto DEVE ter evidências de que a test_policy para adicionar testes foi seguida nas mudanças mais recentes e importantes ao software produzido pelo projeto. [tests_are_added]
    Funcionalidade importante seria tipicamente mencionada nas notas de lançamento. Perfeição não é necessária, apenas evidências de que testes estão sendo tipicamente adicionados na prática ao conjunto de testes automatizados quando nova funcionalidade importante é adicionada ao software produzido pelo projeto.

    The four most recently merged pull requests each shipped tests with the functionality, and the pattern holds because CI enforces it rather than relying on discipline.

    • #3191 (feat, new enumeration primitive) -- 2 of 3 changed files were tests. Patch coverage 100%.
    • #3192 (fix, delete-intent recorded on an API path, plus a shared test helper) -- 3 of 6 files tests. Patch coverage 100%.
    • #3193 (fix, new operator warning on the push path) -- new dedicated test file alongside the feature. Patch coverage 100%.
    • #3195 (guards for the ordering properties #3193 depends on) -- 3 of 3 files tests, an entire PR of tests deliberately split out to keep it reviewable.

    https://github.com/sydlexius/stillwater/pulls?q=is%3Apr+is%3Amerged

    The evidence goes past file counts. These changes were reviewed adversarially, and the review found and rejected tests that passed for reasons unrelated to what they claimed -- a test whose assertion held whether or not the fix was present, an assertion anchored so that real network latency would mask the defect it existed to catch, a comment claiming a drift check the code could not perform. Each was corrected before the change landed, and each new guard was demonstrated red without its fix and green with it.

    #3195 is the clearest illustration of the policy in practice: it exists solely because the ordering properties a merged fix depends on could still be broken silently. Six mutations reproducing prior defects were applied one at a time and each confirmed to make the right test fail. Nothing in it adds functionality; it exists so the functionality cannot regress unnoticed.

    Enforcement rather than intention: patch coverage at 78% is a required status check, and 54 packages carry individual coverage floors, so a change adding functionality without tests fails the build.



    É SUGERIDO que esta política sobre adicionar testes (veja test_policy) seja documentada nas instruções para propostas de mudanças. [tests_documented_added]
    Contudo, mesmo uma regra informal é aceitável desde que os testes estejam sendo adicionados na prática.

    The expectation is stated in the contributor instructions and in the pull request template, and it is enforced mechanically rather than left to discipline.

    CONTRIBUTING.md states that new or changed functionality is expected to arrive with tests in the same pull request, and that this is enforced: patch coverage at 78% is a required status check, so a change adding functionality without tests fails rather than landing. https://github.com/sydlexius/stillwater/blob/main/CONTRIBUTING.md

    The pull request template's test plan asks the author to confirm that new or changed functionality is covered by tests in that pull request: https://github.com/sydlexius/stillwater/blob/main/.github/pull_request_template.md

    Per-package testing standards live in https://github.com/sydlexius/stillwater/tree/main/.github/instructions and apply automatically to any *_test.go file under review, covering what a good test looks like in this codebase rather than only that one should exist.

    The documented standard goes past a coverage percentage. A test guarding a bug fix is expected to be shown failing without the fix -- revert it, confirm red, restore, confirm green -- so a test that guards nothing is caught before it lands. Tests are expected to assert their own preconditions, so a fixture that stops exercising the intended path fails rather than passing vacuously.

    Enforcement backs the documentation: 54 packages carry individual committed coverage floors (https://github.com/sydlexius/stillwater/blob/main/testdata/coverage-floor.json), each checked independently, and mutation testing runs in CI against the test suite itself.


  • Sinalizadores de aviso


    O projeto DEVE habilitar uma ou mais flags de avisos do compilador, um modo de linguagem "seguro", ou usar uma ferramenta "linter" separada para procurar erros de qualidade de código ou erros comuns simples, se houver pelo menos uma ferramenta FLOSS que possa implementar este critério na linguagem selecionada. [warnings]
    Exemplos de flags de avisos do compilador incluem gcc/clang "-Wall". Exemplos de modo de linguagem "seguro" incluem JavaScript "use strict" e perl5 "use warnings". Uma ferramenta "linter" separada é simplesmente uma ferramenta que examina o código-fonte para procurar erros de qualidade de código ou erros comuns simples. Estes são tipicamente habilitados dentro do código-fonte ou instruções de compilação.

    The project runs golangci-lint (GPL-3.0, FLOSS) with 23 linters enabled, configured at https://github.com/sydlexius/stillwater/blob/main/.golangci.yml

    The enabled set is deliberately broader than the default:

    • Correctness: errcheck, errorlint, nilerr, exhaustive, sqlclosecheck, bodyclose, contextcheck, noctx, musttag
    • Security: gosec
    • Static analysis: govet, staticcheck, unused, unparam, unconvert, wastedassign
    • Quality and idiom: gocritic (with style and performance checks enabled beyond its defaults), revive, gocognit for cognitive complexity, prealloc, usestdlibvars, misspell
    • nolintlint, which polices the suppressions themselves so a //nolint cannot be added without a reason

    Suppressions are specific and carry their rationale inline rather than being blanket disables -- for example gosec G104, G117 and G120 are each excluded with a written reason naming why the rule misfires here.

    Beyond the linter: Go's compiler and go vet run over the whole module on every change, and CodeQL performs static analysis on every pull request. Hadolint lints the Dockerfiles, actionlint the GitHub Actions workflows, and stylelint the CSS.

    These are enforced, not advisory. make lint is documented in CONTRIBUTING.md, the pre-commit hook runs golangci-lint on staged packages so a failing change cannot be committed, and lint is a required CI status check. A cognitive-complexity violation blocked a commit during recent work and had to be resolved by extraction rather than suppressed, which is the enforcement working as intended.

    OpenSSF Scorecard independently scores this project 10/10 on its SAST check: https://securityscorecards.dev/viewer/?uri=github.com/sydlexius/stillwater



    O projeto DEVE tratar os avisos. [warnings_fixed]
    Estes são os avisos identificados pela implementação do critério warnings. O projeto deve corrigir avisos ou marcá-los no código-fonte como falsos positivos. Idealmente não haveria avisos, mas um projeto PODE aceitar alguns avisos (tipicamente menos de 1 aviso por 100 linhas ou menos de 10 avisos).

    The codebase is clean: golangci-lint run ./... across the whole module reports 0 issues, measured against current main.

    Warnings are addressed rather than accumulated, because they cannot accumulate. Lint is a required CI status check, so a change introducing a warning fails and does not land, and a pre-commit hook runs golangci-lint on staged packages so a failing change cannot be committed locally either. The gate is not advisory: during recent work a cognitive-complexity violation blocked a commit and had to be resolved by extracting functions, not by suppressing the check.

    Where a rule genuinely misfires, the suppression is specific and carries its reasoning inline rather than being a blanket disable. Every one of the 443 //nolint directives in the codebase names both the specific linter it suppresses and a written reason, for example:

    defer rows.Close() //nolint:errcheck // Close error not actionable on cleanup
    

    That consistency is itself enforced: nolintlint is among the enabled linters, so a suppression cannot be added without naming its linter and giving an explanation. A directive that suppresses nothing is also flagged, which keeps stale suppressions from surviving the code they were written for.

    The three project-level exclusions in .golangci.yml (gosec G104, G117, G120) each carry a written rationale naming why the rule misfires in this codebase, rather than being disabled silently.

    Configuration: https://github.com/sydlexius/stillwater/blob/main/.golangci.yml



    É SUGERIDO que projetos sejam maximamente rigorosos com avisos no software produzido pelo projeto, onde prático. [warnings_strict]
    Alguns avisos não podem ser efetivamente habilitados em alguns projetos. O que é necessário é evidência de que o projeto está se esforçando para habilitar flags de avisos onde puder, de forma que erros sejam detectados cedo.

    The configuration is deliberately stricter than golangci-lint's defaults, and every relaxation is individually justified in the file rather than applied as a blanket disable.

    STRICTER THAN DEFAULT. 23 linters are enabled, well beyond the default set, including several most projects leave off: contextcheck, exhaustive, musttag, nilerr, noctx, sqlclosecheck, unparam, wastedassign, and gocognit for cognitive complexity. gocritic runs with its style and performance tag bundles enabled on top of its defaults.

    RELAXATIONS ARE ARGUED, NOT ASSUMED. Each disabled gocritic check carries a written rationale in .golangci.yml explaining why it does not fit this codebase -- for example octalLiteral is off because the project uses 0o-prefixed file modes and the check also objects to a literal 0; commentedOutCode is off because it false-positives on Go's semantic // Deprecated: markers. The gocritic diagnostic tag is omitted with its reasoning stated: every check in it overlaps something govet or staticcheck already reports, so enabling it would produce duplicate findings rather than new ones. The three gosec exclusions (G104, G117, G120) each name the specific misfire.

    That is the evidence the criterion asks for: the decisions are visible and defensible, so a future contributor can re-litigate any of them against the reasoning rather than guessing why a check is off.

    SUPPRESSIONS ARE POLICED. nolintlint is enabled, so an inline suppression cannot be added without naming its linter and giving a reason, and a directive that suppresses nothing is flagged. All 443 //nolint directives in the codebase carry both.

    BEYOND THE LINTER. The whole module is built and vetted on every change; CodeQL analyses every pull request; the race detector runs over the suite in CI; mutation testing checks the tests themselves detect changed behaviour; Hadolint, actionlint and stylelint cover the Dockerfiles, workflows and CSS. Lint is a required status check and a pre-commit hook runs it on staged packages, so strictness is enforced at both ends.

    Current result: golangci-lint run ./... reports 0 issues across the module.

    https://github.com/sydlexius/stillwater/blob/main/.golangci.yml


 Segurança 14/16 ●

  • Conhecimento de desenvolvimento seguro


    O projeto DEVE ter pelo menos um desenvolvedor principal que saiba como projetar software seguro. (Veja 'details' para os requisitos exatos.) [know_secure_design]
    Isto requer entender os seguintes princípios de projeto, incluindo os 8 princípios de Saltzer and Schroeder:
    • economia de mecanismo (mantenha o projeto tão simples e pequeno quanto prático, por exemplo, adotando simplificações amplas)
    • padrões à prova de falhas (decisões de acesso devem negar por padrão, e a instalação dos projetos deve ser segura por padrão)
    • mediação completa (todo acesso que possa ser limitado deve ser verificado quanto à autoridade e não ser contornável)
    • projeto aberto (mecanismos de segurança não devem depender da ignorância do invasor sobre seu projeto, mas sim em informações mais facilmente protegidas e alteradas como chaves e senhas)
    • separação de privilégios (idealmente, acesso a objetos importantes deve depender de mais de uma condição, de forma que derrotar um sistema de proteção não permita acesso completo. Por exemplo, autenticação multifator, como exigir tanto uma senha quanto um token de hardware, é mais forte que autenticação de fator único)
    • menor privilégio (processos devem operar com o menor privilégio necessário)
    • menor mecanismo comum (o projeto deve minimizar os mecanismos comuns a mais de um usuário e dos quais todos os usuários dependem, por exemplo, diretórios para arquivos temporários)
    • aceitabilidade psicológica (a interface humana deve ser projetada para facilidade de uso - projetar para "menor surpresa" pode ajudar)
    • superfície de ataque limitada (a superfície de ataque - o conjunto dos diferentes pontos onde um invasor pode tentar entrar ou extrair dados - deve ser limitada)
    • validação de entrada com listas de permissões (entradas devem tipicamente ser verificadas para determinar se são válidas antes de serem aceitas; esta validação deve usar listas de permissões (que aceitam apenas valores conhecidamente bons), não listas de negação (que tentam listar valores conhecidamente ruins)).
    Um "desenvolvedor principal" em um projeto é qualquer pessoa que esteja familiarizada com a base de código do projeto, esteja confortável fazendo mudanças nela, e seja reconhecida como tal pela maioria dos outros participantes no projeto. Um desenvolvedor principal tipicamente faria várias contribuições ao longo do último ano (via código, documentação ou respondendo perguntas). Desenvolvedores seriam tipicamente considerados desenvolvedores principais se iniciaram o projeto (e não deixaram o projeto há mais de três anos), têm a opção de receber informações em um canal privado de relato de vulnerabilidades (se houver um), podem aceitar commits em nome do projeto, ou realizar lançamentos finais do software do projeto. Se há apenas um desenvolvedor, esse indivíduo é o desenvolvedor principal. Muitos livros e cursos estão disponíveis para ajudá-lo a entender como desenvolver software mais seguro e discutir projeto. Por exemplo, o curso Secure Software Development Fundamentals é um conjunto gratuito de três cursos que explicam como desenvolver software mais seguro (é gratuito se você auditar; por uma taxa extra você pode obter um certificado para provar que aprendeu o material).

    ...pending completion of the OpenSSF Secure Software Development Fundamentals course.

    The project has a single primary developer, who initiated it, accepts all commits, performs releases, and receives private vulnerability reports. That developer has not completed formal secure-design training and does not claim familiarity with the Saltzer and Schroeder principles by name. Since this criterion asks what a developer understands rather than what the codebase contains, answering Met on the strength of the implementation would be asserting the knowledge rather than evidencing it. It is recorded honestly as unmet.

    The plan to meet it is the course this criterion names -- the OpenSSF Secure Software Development Fundamentals, audited free -- which also addresses know_common_errors.

    For context, several of the principles are applied in the codebase today, though a number of them were arrived at through adversarial review and automated analysis rather than from first principles:

    • Fail-safe defaults: destructive checks are written as positive allowlists rather than negated safe-lists, and an image-repair path that cannot positively identify the slot it means to overwrite adds rather than overwrites, on the reasoning that one extra copy is recoverable and a destroyed image is not.
    • Complete mediation: authentication, CSRF protection and rate limiting are router middleware, so a new endpoint is covered by construction rather than by the author remembering.
    • Open design: provider API keys are encrypted at rest with AES-256-GCM, the key is a 0600 file rather than an environment value, and the whole design is public under GPL-3.0.
    • Least privilege: CI workflow tokens are scoped per job, since job-level permissions replace rather than extend workflow-level ones, and checkouts run with persist-credentials disabled.
    • Input validation with allowlists: path inputs are validated against an allowlist of a single path element rather than a denylist of traversal forms.
    • Limited attack surface: SECURITY.md defines scope explicitly; the application is self-hosted with no outbound telemetry and a minimal vendored JavaScript footprint rather than an npm dependency tree.

    External analysis supports the implementation -- CodeQL on every pull request, gosec among 23 enabled linters, govulncheck in CI, Sigstore-signed releases, and an OpenSSF Scorecard of 9.0/10 -- but external analysis is not the developer knowledge this criterion asks about, so the criterion is answered on its own terms.



    Pelo menos um dos desenvolvedores principais do projeto DEVE conhecer tipos comuns de erros que levam a vulnerabilidades neste tipo de software, bem como pelo menos um método para combater ou mitigar cada um deles. [know_common_errors]
    Exemplos (dependendo do tipo de software) incluem injeção SQL, injeção de SO, estouro clássico de buffer, cross-site scripting, autenticação ausente e autorização ausente. Veja o CWE/SANS top 25 ou OWASP Top 10 para listas comumente usadas. Muitos livros e cursos estão disponíveis para ajudá-lo a entender como desenvolver software mais seguro e discutir erros comuns de implementação que levam a vulnerabilidades. Por exemplo, o curso Secure Software Development Fundamentals é um conjunto gratuito de três cursos que explicam como desenvolver software mais seguro (é gratuito se você auditar; por uma taxa extra você pode obter um certificado para provar que aprendeu o material).

    ...pending completion of the OpenSSF Secure Software Development Fundamentals course.

    The project is developed by a single primary developer, who has not completed formal secure-development training, and this criterion asks what a developer knows rather than what the codebase contains. Answering Met on the strength of the implemented mitigations would be asserting knowledge rather than evidencing it, so it is recorded honestly as unmet.

    The plan to meet it is the course this criterion names -- the OpenSSF Secure Software Development Fundamentals, audited free -- which also addresses know_secure_design.

    For context, mitigations for the common classes are implemented and enforced in the project today, several of them structurally rather than per-site: authentication, CSRF protection, and rate limiting applied as router middleware so a new endpoint is covered by construction; provider API keys encrypted at rest with AES-256-GCM under a 0600 key file rather than an environment value; input validated at the API boundary, with path inputs checked against an allowlist of one path element rather than a denylist of traversal forms; parameterized SQL throughout.

    These are backed by automated checks rather than vigilance: CodeQL on every pull request, gosec among 23 enabled linters, govulncheck in CI, and Dependabot for dependency advisories. That is why the codebase scores well on external analysis -- OpenSSF Scorecard rates it 9.0/10 -- but external analysis is not the same as the developer knowledge this criterion asks about, and the criterion is answered on its own terms.


  • Usar práticas criptográficas boas e básicas

    Observe que alguns softwares não precisam usar mecanismos criptográficos. Se o seu projeto produzir software que (1) inclui, ativa ou habilita funcionalidade de criptografia, e (2) pode ser liberado dos Estados Unidos (EUA) para fora dos EUA ou para um não cidadão dos EUA, você pode ser legalmente obrigado a tomar algumas etapas extras. Normalmente isso envolve apenas o envio de um e-mail. Para mais informações, consulte a seção de criptografia de Understanding Open Source Technology & US Export Controls.

    O software produzido pelo projeto DEVE usar, por padrão, apenas protocolos criptográficos e algoritmos que são publicamente publicados e revisados por especialistas (se protocolos criptográficos e algoritmos forem usados). [crypto_published]
    Esses critérios criptográficos nem sempre se aplicam porque alguns softwares não têm necessidade de usar diretamente capacidades criptográficas.

    Every cryptographic algorithm the project uses is publicly published, standardised and expert-reviewed, and all of them come from Go's standard library or the Go project's supplementary x/crypto module. Nothing is home-grown.

    • Secrets at rest: AES-256-GCM (FIPS 197 for AES, NIST SP 800-38D for GCM) via crypto/aes and crypto/cipher, used to encrypt provider API keys. Implementation: https://github.com/sydlexius/stillwater/blob/main/internal/encryption/encryption.go
    • Password storage: bcrypt (Provos and Mazieres, USENIX 1999) via golang.org/x/crypto/bcrypt, at the library's default cost. Passwords are pre-hashed before bcrypt to avoid its 72-byte input truncation.
    • Transport: TLS via crypto/tls, with certificate handling through crypto/x509.
    • Signatures and keys: ECDSA (crypto/ecdsa with crypto/elliptic) and RSA (crypto/rsa), as required for OIDC token verification.
    • Hashing and message authentication: SHA-256 (FIPS 180-4) via crypto/sha256, and HMAC (RFC 2104, FIPS 198-1) via crypto/hmac.
    • Randomness: crypto/rand, the cryptographically secure source, rather than math/rand.
    • Constant-time comparison: crypto/subtle, so secret comparisons do not leak by timing.

    No custom cipher, construction, mode, or key-derivation scheme is defined anywhere in the project. Where a cryptographic operation is needed, the standard library primitive is used directly.

    Supporting controls: the encryption key is stored as a file with 0600 permissions rather than an environment variable, so it does not appear in a process listing or in inherited environments. gosec is among the 23 linters enabled in CI, CodeQL analyses every pull request, and govulncheck runs against the dependency graph -- so a weak or deprecated primitive would be flagged rather than lingering unnoticed.



    Se o software produzido pelo projeto for uma aplicação ou biblioteca, e seu propósito principal não for implementar criptografia, então ele DEVERIA apenas chamar software especificamente projetado para implementar funções criptográficas; ele NÃO DEVERIA reimplementar o seu próprio. [crypto_call]

    Stillwater is a metadata and image manager for self-hosted media servers; implementing cryptography is not its purpose, and it does not attempt to.

    Every cryptographic operation calls into software written specifically to implement it -- Go's standard library (crypto/aes, crypto/cipher, crypto/tls, crypto/x509, crypto/sha256, crypto/hmac, crypto/rand, crypto/subtle, crypto/ecdsa, crypto/rsa) and the Go project's supplementary golang.org/x/crypto/bcrypt.

    No cipher, mode, hash, MAC, key-derivation function, or random-number generator is implemented in this codebase. The encryption path composes standard primitives in the documented way -- aes.NewCipher into cipher.NewGCM, with the nonce drawn from crypto/rand -- rather than assembling anything bespoke: https://github.com/sydlexius/stillwater/blob/main/internal/encryption/encryption.go

    Where the project had a choice between using a primitive correctly and working around one of its properties, it used the primitive: passwords are pre-hashed before bcrypt to avoid its 72-byte input truncation, rather than substituting a hand-rolled scheme.

    This is enforced as well as intended. gosec is among the 23 linters enabled in CI and flags weak or misused cryptographic primitives, CodeQL analyses every pull request, and govulncheck runs against the dependency graph -- so an advisory affecting x/crypto surfaces as a CI finding rather than going unnoticed. Two such advisories were resolved this way by upgrading the dependency rather than patching around it.



    Toda funcionalidade no software produzido pelo projeto que depende de criptografia DEVE ser implementável usando FLOSS. [crypto_floss]

    Every cryptographic dependency is FLOSS, and none is optional or substitutable for a proprietary alternative.

    • Go standard library crypto (crypto/aes, crypto/cipher, crypto/tls, crypto/x509, crypto/sha256, crypto/hmac, crypto/rand, crypto/subtle, crypto/ecdsa, crypto/rsa) -- BSD-3-Clause.
    • golang.org/x/crypto/bcrypt, from the Go project -- BSD-3-Clause.

    Both ship with, or are fetched as, ordinary module dependencies. There is no proprietary cryptographic library, no hardware security module requirement, no vendor SDK, and no paid service anywhere in the cryptographic path.

    The algorithms themselves are open standards with multiple independent FLOSS implementations, so nothing here is tied to a single provider: AES (FIPS 197) and GCM (NIST SP 800-38D), bcrypt (published by Provos and Mazieres, USENIX 1999), TLS and X.509 (IETF), SHA-256 (FIPS 180-4), HMAC (RFC 2104), ECDSA and RSA. A reimplementation against any conforming FLOSS crypto library would interoperate with data this project has already written.

    The build reflects that: the whole project builds from source with FLOSS tooling only (Go, templ, Tailwind, Node, Make, git), so a user can compile and run every cryptographic path themselves without acquiring anything proprietary. Encrypted data is readable by any AES-256-GCM implementation given the key, and the key is a plain file rather than something sealed to a proprietary keystore -- so a user is not locked in by the encryption at rest.

    The project is licensed GPL-3.0: https://github.com/sydlexius/stillwater/blob/main/LICENSE



    Os mecanismos de segurança dentro do software produzido pelo projeto DEVEM usar comprimentos de chave padrão que pelo menos atendam aos requisitos mínimos do NIST até o ano de 2030 (conforme declarado em 2012). DEVE ser possível configurar o software para que comprimentos de chave menores sejam completamente desabilitados. [crypto_keylength]
    Esses comprimentos mínimos de bits são: chave simétrica 112, módulo de fatoração 2048, chave de logaritmo discreto 224, grupo logarítmico discreto 2048, curva elíptica 224 e hash 224 (hashing de senha não é coberto por este comprimento de bits, mais informações sobre hashing de senha podem ser encontradas no critério crypto_password_storage). Veja https://www.keylength.com para uma comparação de recomendações de comprimento de chave de várias organizações. O software PODE permitir comprimentos de chave menores em algumas configurações (idealmente não permitiria, já que isso permite ataques de downgrade, mas comprimentos de chave mais curtos são às vezes necessários para interoperabilidade).

    Every default exceeds the stated 2030 minimums, and shorter lengths are not configurable -- they are rejected outright rather than merely discouraged.

    SYMMETRIC (minimum 112). AES-256, so 256 bits. The key length is not a setting: the encryptor requires exactly 32 bytes and returns an error otherwise, so a shorter key cannot be configured, supplied, or fallen back to. A generated key is drawn from crypto/rand at the full 32 bytes. https://github.com/sydlexius/stillwater/blob/main/internal/encryption/encryption.go

    ELLIPTIC CURVE (minimum 224). P-256, so 256 bits, used for the ACME account and certificate keys. The curve is fixed in code rather than exposed as an option.

    TRANSPORT. The HTTPS listener sets MinVersion: tls.VersionTLS13, which is stronger than this criterion requires: TLS 1.3 removes the weak cipher suites and short-key key-exchange groups entirely, so a downgrade to a smaller keylength is not reachable through negotiation. Older protocol versions are refused rather than deprioritised.

    FACTORING MODULUS AND DISCRETE LOG (minimum 2048). The project does not generate RSA or finite-field Diffie-Hellman keys of its own. crypto/rsa appears only for verifying OIDC provider tokens, where the key is the identity provider's, and crypto/x509 for certificate handling. Where the project chooses, it chooses ECDSA P-256.

    HASH (minimum 224). SHA-256, so 256 bits, via crypto/sha256. No shorter digest is used anywhere; SHA-1 and MD5 do not appear in the cryptographic path.

    CONFIGURABILITY OF SMALLER LENGTHS. There is none, by design. No setting, environment variable, or flag lowers any of the above. The AES key length is enforced with an explicit error, the curve and hash are compile-time choices, and the TLS floor is set at the listener. Since the project has no interoperability requirement that would justify a weaker option, the downgrade path this criterion permits simply does not exist.

    gosec, which flags weak cryptographic parameters, is among the 23 linters enabled in CI, and CodeQL analyses every pull request.



    Os mecanismos de segurança padrão dentro do software produzido pelo projeto NÃO DEVEM depender de algoritmos criptográficos quebrados (por exemplo, MD4, MD5, DES único, RC4, Dual_EC_DRBG), ou usar modos de cifra que são inadequados ao contexto, a menos que sejam necessários para implementar um protocolo interoperável (onde o protocolo implementado é a versão mais recente desse padrão amplamente suportado pelo ecossistema de rede, esse ecossistema requer o uso de tal algoritmo ou modo, e esse ecossistema não oferece nenhuma alternativa mais segura). A documentação DEVE descrever quaisquer riscos de segurança relevantes e quaisquer mitigações conhecidas se esses algoritmos ou modos quebrados forem necessários para um protocolo interoperável. [crypto_working]
    O modo ECB é quase nunca apropriado porque revela blocos idênticos dentro do texto cifrado conforme demonstrado pelo pinguim ECB, e o modo CTR é frequentemente inadequado porque não realiza autenticação e causa duplicatas se o estado de entrada for repetido. Em muitos casos é melhor escolher um modo de algoritmo de cifra de bloco projetado para combinar sigilo e autenticação, por exemplo, Galois/Counter Mode (GCM) e EAX. Projetos PODEM permitir que usuários habilitem mecanismos quebrados (por exemplo, durante a configuração) onde necessário para compatibilidade, mas então os usuários sabem que estão fazendo isso.

    No broken algorithm and no inappropriate cipher mode is used anywhere in the project's security mechanisms, and none is needed for interoperability.

    VERIFIED ABSENT. A scan of the codebase for MD4, MD5, SHA-1, single DES, RC4, and Dual_EC_DRBG returns nothing outside of test files -- none of them appears in the cryptographic path at all. There is consequently no interoperability exception to document, and no configuration option that would enable one.

    CIPHER MODE. Secrets at rest use AES-256-GCM, an AEAD mode that provides authentication alongside confidentiality, which is the combination this criterion recommends. ECB, CBC, and raw CTR are not used anywhere: the codebase contains no call to cipher.NewCBCEncrypter, NewCTR, or any ECB construction. The nonce is drawn from crypto/rand per encryption rather than reused or derived, so GCM's requirement for nonce uniqueness is met by construction. https://github.com/sydlexius/stillwater/blob/main/internal/encryption/encryption.go

    THE REST OF THE PATH. SHA-256 for hashing, HMAC for message authentication, bcrypt for password storage, ECDSA on P-256 for certificate keys, and TLS 1.3 as the enforced transport floor -- TLS 1.3 having removed the weak cipher suites, RC4, and CBC-mode suites from negotiation entirely, so a downgrade to a broken algorithm is not reachable.

    ONE CLARIFICATION, TO PRE-EMPT A FALSE POSITIVE. The project computes a 64-bit perceptual hash (dHash) over images to detect visually duplicate artwork: https://github.com/sydlexius/stillwater/blob/main/internal/image/hash.go . That is an image-similarity function, not a cryptographic one. It protects nothing, guards no security decision, and is never used for authentication, integrity, or as a security boundary -- comparing artwork for near-duplicates is its only purpose. Its short digest is therefore not a cryptographic weakness.

    ENFORCEMENT. gosec, which flags weak and deprecated cryptographic primitives, is among the 23 linters enabled in CI and runs on every change; CodeQL analyses every pull request; govulncheck runs against the dependency graph. A broken primitive introduced later would fail the build rather than reach a release.



    Os mecanismos de segurança padrão dentro do software produzido pelo projeto NÃO DEVERIAM depender de algoritmos criptográficos ou modos com fraquezas sérias conhecidas (por exemplo, o algoritmo de hash criptográfico SHA-1 ou o modo CBC em SSH). [crypto_weaknesses]
    Preocupações sobre o modo CBC em SSH são discutidas em CERT: SSH CBC vulnerability.

    Nothing in the project's security mechanisms depends on an algorithm or mode with a known serious weakness.

    SHA-1 does not appear in the cryptographic path at all -- verified by scanning the codebase. Hashing is SHA-256 throughout, and message authentication is HMAC.

    CBC is not used in any form. Secrets at rest use AES-256-GCM, an authenticated mode, so the padding-oracle and malleability problems that motivate the concern about CBC do not arise: a ciphertext that has been tampered with fails authentication rather than decrypting into attacker-influenced plaintext.

    The transport floor is TLS 1.3, set explicitly at the listener rather than left to negotiation. This is stronger than avoiding weak choices individually: TLS 1.3 removed CBC-mode cipher suites, RC4, static RSA key exchange, and renegotiation from the protocol, so the weaknesses this criterion is concerned with are not reachable by downgrade even if a client requests them. Earlier protocol versions are refused, not merely deprioritised.

    Elliptic-curve work uses P-256 rather than any of the curves with questioned provenance, and randomness comes from crypto/rand -- never math/rand, and never a DRBG of uncertain design.

    Passwords are stored with bcrypt at the library's default cost, and are pre-hashed before bcrypt so that its 72-byte input truncation cannot silently discard part of a long passphrase.

    The project does not implement or expose SSH, so the CBC-in-SSH case this criterion cites does not apply.

    Enforcement rather than intent: gosec, which flags weak and deprecated primitives, is among the 23 linters enabled in CI; CodeQL analyses every pull request; govulncheck runs against the dependency graph, and two golang.org/x/crypto advisories were resolved by upgrading the dependency rather than working around them.



    Os mecanismos de segurança dentro do software produzido pelo projeto DEVERIAM implementar sigilo perfeito para frente para protocolos de acordo de chave, de modo que uma chave de sessão derivada de um conjunto de chaves de longo prazo não possa ser comprometida se uma das chaves de longo prazo for comprometida no futuro. [crypto_pfs]

    The only key-agreement protocol the project uses is TLS, and it is pinned to TLS 1.3, which provides forward secrecy unconditionally.

    The HTTPS listener sets MinVersion: tls.VersionTLS13 explicitly rather than leaving the floor to negotiation: https://github.com/sydlexius/stillwater/blob/main/internal/server/listeners.go

    This is stronger than selecting forward-secret cipher suites within an older protocol. TLS 1.3 removed static RSA and static Diffie-Hellman key exchange from the protocol entirely, so every handshake is an ephemeral (EC)DHE exchange by construction. There is no cipher-suite configuration, downgrade path, or interoperability option through which a non-forward-secret handshake could be negotiated -- a client offering only older mechanisms is refused rather than accommodated.

    Compromise of the server's long-term private key at some future point therefore does not expose previously recorded sessions: the per-session keys derive from ephemeral key shares that are discarded when the session ends and are never transmitted.

    The HTTP/3 listener shares the same TLS material and the same floor; QUIC mandates TLS 1.3 in any case, and quic-go enforces that internally.

    The project implements no other key-agreement protocol. Secrets at rest are encrypted with a locally held symmetric key (AES-256-GCM) rather than through a key-agreement exchange, so forward secrecy is not applicable to that path -- there are no session keys and no long-term keys negotiated between parties.

    Outbound connections to metadata providers and to Emby, Jellyfin, and Lidarr use Go's standard net/http client, whose default TLS configuration prefers forward-secret suites and negotiates TLS 1.3 with any server that supports it.



    Se o software produzido pelo projeto causar o armazenamento de senhas para autenticação de usuários externos, as senhas DEVEM ser armazenadas como hashes iterados com um salt por usuário usando um algoritmo de extensão de chave (iterado) (por exemplo, Argon2id, Bcrypt, Scrypt ou PBKDF2). Veja também OWASP Password Storage Cheat Sheet. [crypto_password_storage]
    Este critério aplica-se apenas quando o software está aplicando autenticação de usuários usando senhas para usuários externos (também conhecida como autenticação de entrada), como aplicações web do lado do servidor. Não se aplica em casos onde o software armazena senhas para autenticar em outros sistemas (também conhecida como autenticação de saída, por exemplo, o software implementa um cliente para algum outro sistema), já que pelo menos partes desse software devem ter acesso frequentemente à senha não hasheada.

    Local user passwords are stored as bcrypt hashes -- an iterated, salted, key-stretching algorithm, and one of the algorithms this criterion names.

    Implementation: bcrypt.GenerateFromPassword(PrehashPassword(password), bcrypt.DefaultCost) via golang.org/x/crypto/bcrypt. https://github.com/sydlexius/stillwater/blob/main/internal/auth/user.go

    • ITERATED: bcrypt is a deliberately slow key-stretching function; the work factor is the library's default cost rather than a lowered value.
    • PER-USER SALT: bcrypt generates a random salt per invocation and stores it within the resulting hash, so two users with the same password produce different stored values.
    • The plaintext password is never stored, and never logged.

    PRE-HASHING, AND WHY. The password is passed through SHA-256 and hex-encoded before bcrypt, rather than handed to bcrypt directly. bcrypt silently truncates its input at 72 bytes, so a long passphrase would otherwise have its tail discarded without any error -- two distinct passphrases sharing a 72-byte prefix would authenticate interchangeably. Pre-hashing to a fixed-length 64-character hex digest removes that truncation entirely, so the full passphrase contributes to the stored hash. This is the construction the OWASP Password Storage Cheat Sheet recommends for bcrypt, and it does not weaken the stretching: bcrypt still performs its full cost-factor work over the digest, and the per-invocation salt is unchanged.

    TIMING. Login compares against a bcrypt hash computed once at default cost for the unknown-user case, so an unregistered username costs the same as a registered one and does not leak account existence by response time.

    SCOPE. This applies to local accounts. The project also supports OIDC and federated authentication against a media server, where no password is stored at all -- the identity provider or media server holds the credential. Credentials the project stores for OUTBOUND authentication to third-party services (provider API keys) are encrypted with AES-256-GCM rather than hashed, since they must be recoverable to be used, which is the outbound case this criterion explicitly excludes.



    Os mecanismos de segurança dentro do software produzido pelo projeto DEVEM gerar todas as chaves criptográficas e nonces usando um gerador de números aleatórios criptograficamente seguro, e NÃO DEVEM fazê-lo usando geradores que são criptograficamente inseguros. [crypto_random]
    Um gerador de números aleatórios criptograficamente seguro pode ser um gerador de números aleatórios de hardware, ou pode ser um gerador de números pseudo-aleatórios criptograficamente seguro (CSPRNG) usando um algoritmo como Hash_DRBG, HMAC_DRBG, CTR_DRBG, Yarrow ou Fortuna. Exemplos de chamadas para geradores de números aleatórios seguros incluem o java.security.SecureRandom do Java e o window.crypto.getRandomValues do JavaScript. Exemplos de chamadas para geradores de números aleatórios inseguros incluem o java.util.Random do Java e o Math.random do JavaScript.

    Every cryptographic key, nonce, token, and secret is generated from crypto/rand, Go's cryptographically secure random source, which draws from the operating system CSPRNG.

    Security-relevant generation sites all use it:

    • The AES-256 encryption key, when generated (internal/encryption/encryption.go)
    • The GCM nonce, drawn fresh per encryption
    • Session and authentication tokens (internal/auth/)
    • CSRF tokens (internal/api/middleware/csrf.go)
    • OIDC state and nonce values (internal/auth/provider_oidc.go)
    • Invitation tokens (internal/auth/invite.go)
    • ACME account and certificate keys (internal/server/cert_manager_lego.go)
    • Settings export material (internal/settingsio/export.go)

    math/rand is used in exactly two places, and neither is a security mechanism. Both are annotated inline with the reason:

    • internal/watcher/probe.go generates a filename suffix for a filesystem write-probe -- a temporary file the watcher creates to test whether a directory is writable. Unpredictability is not a property it needs.
    • internal/provider/retry.go computes jitter for retry backoff against third-party metadata APIs, so concurrent retries do not synchronise. Jitter does not need to be unguessable.

    Neither generates a key, nonce, token, or any value an attacker could exploit by predicting. Both carry a //nolint:gosec directive naming the linter and stating why the rule does not apply, which is the project's convention for every suppression.

    That distinction is enforced rather than trusted: gosec's G404 rule flags every use of a non-cryptographic RNG, and gosec is among the 23 linters enabled in CI running on every change. A new math/rand call in a security path would fail the build unless someone explicitly suppressed it with a written justification, which is visible in review.


  • Entrega protegida contra ataques man-in-the-middle (MITM)


    O projeto DEVE usar um mecanismo de entrega que contraponha ataques MITM. Usar https ou ssh+scp é aceitável. [delivery_mitm]
    Um mecanismo ainda mais forte é liberar o software com pacotes assinados digitalmente, já que isso mitiga ataques no sistema de distribuição, mas isso só funciona se os usuários puderem estar confiantes de que as chaves públicas para assinaturas estão corretas e se os usuários realmente verificarão a assinatura.

    HTTPS is used throughout and additionally by digital signatures on every release artifact.

    TRANSPORT. Every distribution channel is HTTPS-only:

    Go module dependencies are fetched over HTTPS and verified against go.sum, so a tampered dependency fails the build rather than being silently accepted.

    SIGNATURES, the stronger mechanism this criterion describes. Release artifacts are signed with cosign (Sigstore) as part of the release workflow, and SLSA provenance attestation is generated at release level: https://github.com/sydlexius/stillwater/blob/main/.github/workflows/release.yml

    Sigstore is keyless -- signatures are bound to the GitHub Actions workflow identity that produced them and recorded in the public Rekor transparency log. That addresses the caveat in this criterion's own wording: a user does not need to obtain and trust a maintainer's public key out of band, since verification checks the signing identity against the transparency log rather than against a key the user must first acquire securely. Checksums are published alongside the artifacts, and the multi-architecture container manifest is signed as well as the individual images.

    OpenSSF Scorecard independently confirms this, scoring the project 10/10 on Signed-Releases: "5 out of the last 5 releases have a total of 10 signed artifacts" -- https://securityscorecards.dev/viewer/?uri=github.com/sydlexius/stillwater



    Um hash criptográfico (por exemplo, um sha1sum) NÃO DEVE ser recuperado por http e usado sem verificar uma assinatura criptográfica. [delivery_unsigned]
    Esses hashes podem ser modificados durante o trânsito.

    Nothing in the project retrieves a cryptographic hash over plaintext HTTP, in the build, in CI, or at runtime.

    BUILD AND CI. A scan of the workflows finds no plaintext http:// fetch of any kind. Everything the build retrieves comes over HTTPS, and each class is verified by a mechanism stronger than a bare downloaded checksum:

    • Go module dependencies are fetched over HTTPS and verified against the committed go.sum, which is itself in version control rather than downloaded alongside the artifact. A tampered module fails the build.
    • npm dependencies are pinned in package-lock.json with integrity hashes, likewise committed.
    • All 155 GitHub Actions references are pinned to commit SHAs rather than mutable tags, so a compromised or moved tag cannot substitute different code. OpenSSF Scorecard confirms this independently, scoring 10/10 on Pinned-Dependencies for Actions.
    • Container base images are pinned in the Dockerfiles.

    RUNTIME. The application fetches metadata and artwork from third-party providers over HTTPS, and connects to Emby, Jellyfin and Lidarr over the scheme the operator configures. It does not download a checksum or hash file from any source and act on it, so the situation this criterion describes does not arise.

    The one place the project handles checksums is in the opposite direction: the release workflow PUBLISHES checksums alongside its artifacts, and those artifacts are additionally signed with cosign (Sigstore) with SLSA provenance attestation. A consumer verifying a release therefore checks a signature bound to the producing workflow identity and recorded in the public Rekor transparency log, rather than trusting a hash retrieved over the wire.


  • Vulnerabilidades conhecidas publicamente corrigidas


    NÃO DEVE haver vulnerabilidades não corrigidas de severidade média ou superior que sejam publicamente conhecidas por mais de 60 dias. [vulnerabilities_fixed_60_days]
    A vulnerabilidade deve ser corrigida e lançada pelo próprio projeto (as correções podem ser desenvolvidas em outro lugar). Uma vulnerabilidade se torna publicamente conhecida (para este propósito) uma vez que tem um CVE com informações lançadas publicamente sem paywall (relatadas, por exemplo, no National Vulnerability Database) ou quando o projeto foi informado e a informação foi liberada ao público (possivelmente pelo projeto). Uma vulnerabilidade é considerada de severidade média ou superior se sua pontuação qualitativa base do Common Vulnerability Scoring System (CVSS) for média ou superior. Nas versões 2.0 a 3.1 do CVSS, isso é equivalente a uma pontuação CVSS de 4.0 ou superior. Os projetos podem usar a pontuação CVSS conforme publicada em um banco de dados de vulnerabilidades amplamente usado (como o National Vulnerability Database) usando a versão mais recente do CVSS relatada nesse banco de dados. Os projetos podem, em vez disso, calcular a severidade eles mesmos usando a versão mais recente do CVSS no momento da divulgação da vulnerabilidade, se as entradas de cálculo forem publicamente reveladas uma vez que a vulnerabilidade seja publicamente conhecida. Nota: isso significa que os usuários podem ficar vulneráveis a todos os atacantes em todo o mundo por até 60 dias. Este critério é frequentemente muito mais fácil de atender do que o que o Google recomenda em Rebooting responsible disclosure, porque o Google recomenda que o período de 60 dias comece quando o projeto é notificado mesmo se o relatório não for público. Observe também que este critério de selo, como outros critérios, aplica-se ao projeto individual. Alguns projetos fazem parte de organizações guarda-chuva maiores ou projetos maiores, possivelmente em múltiplas camadas, e muitos projetos alimentam seus resultados para outras organizações e projetos como parte de uma cadeia de suprimentos potencialmente complexa. Um projeto individual geralmente não pode controlar o resto, mas um projeto individual pode trabalhar para lançar uma correção de vulnerabilidade de forma oportuna. Portanto, focamos apenas no tempo de resposta do projeto individual. Uma vez que uma correção esteja disponível do projeto individual, outros podem determinar como lidar com a correção (por exemplo, eles podem atualizar para a versão mais recente ou podem aplicar apenas a correção como uma solução cherry-picked).

    There are no unpatched vulnerabilities of any severity, publicly known or otherwise.

    Verified against the live repository:

    • Published security advisories: 0 (https://github.com/sydlexius/stillwater/security/advisories)
    • Open Dependabot alerts: 0
    • Open code-scanning (CodeQL) alerts: 0
    • No CVE has been assigned against the project; NIST's CPE dictionary returns no entry for either the product or the vendor name, as expected for a project with no published CVE.

    There has consequently never been a 60-day window to exceed.

    Vulnerabilities are surfaced continuously rather than waiting on an external report: CodeQL analyses every pull request, govulncheck runs in CI against the dependency graph, gosec is among the 23 linters enabled on every change, and Dependabot is configured for dependency updates.

    Dependency advisories are acted on promptly rather than accumulating. Two golang.org/x/crypto advisories surfaced by govulncheck were resolved by upgrading the dependency the same day they were identified, ahead of any external scanner flagging them. One further advisory affecting a transitive dependency has no fixed version published upstream; the affected subpackage is never imported by this project, so it is unreachable here, and that determination was made by call-path analysis rather than by version range alone.

    If a vulnerability is reported, SECURITY.md commits to an initial acknowledgement within 72 hours and a fix released as soon as practical, typically within 14 days for critical issues -- well inside the 60-day bound this criterion sets: https://github.com/sydlexius/stillwater/blob/main/SECURITY.md



    Os projetos DEVERIAM corrigir todas as vulnerabilidades críticas rapidamente após serem relatadas. [vulnerabilities_critical_fixed]

    No critical vulnerability has been reported against the project, so there is no remediation record to point to. Verified live: zero published security advisories, zero open Dependabot alerts, zero open CodeQL alerts, and no CVE assigned.

    What can be evidenced is the response speed on the security findings the project has actually had.

    Dependency advisories are fixed the day they surface. Two golang.org/x/crypto advisories were identified by govulncheck and resolved by upgrading the dependency within hours, ahead of any external scanner flagging them. A third advisory affecting a transitive dependency has no fixed version published upstream; call-path analysis confirmed the affected subpackage is never imported here, so it is unreachable rather than unaddressed, and that determination is recorded rather than assumed.

    Findings from code review are treated the same way. A recent change introduced a data-loss window -- a cleanup sweep could delete another concurrent operation's in-progress staging file, turning a recoverable failure into permanent loss. It was found in review, fixed the same session with a proof that reproduces the loss when the fix is removed, and the fix itself was then re-reviewed rather than trusted.

    The commitment for a reported vulnerability is published in advance: an initial acknowledgement within 72 hours, and a fix released as soon as practical, typically within 14 days for critical issues. https://github.com/sydlexius/stillwater/blob/main/SECURITY.md

    Detection is continuous rather than waiting on a report -- CodeQL on every pull request, govulncheck in CI, gosec among 23 enabled linters, and Dependabot for dependency updates -- and releases are frequent (four stable releases in the past month), so a fix does not wait on a distant release train to reach users.


  • Outras questões de segurança


    Os repositórios públicos NÃO DEVEM vazar uma credencial privada válida (por exemplo, uma senha funcionando ou chave privada) que se destina a limitar o acesso público. [no_leaked_credentials]
    Um projeto PODE vazar credenciais "de amostra" para testes e bancos de dados sem importância, desde que não sejam destinadas a limitar o acesso público.

    No valid private credential is present in the repository.

    GitHub secret scanning is ENABLED on the repository, so a committed credential matching a known provider pattern is detected and reported automatically rather than depending on anyone noticing. Push protection and scanning run against the full history, not just new commits.

    Nothing sensitive is tracked. No .pem, .key, .p12, SSH private key, or encryption key file exists in version control -- the only match for a key-shaped filename is a Go test that asserts the encryption key file is created with 0600 permissions, which contains no key material. .gitignore excludes .env and .env.*, all SQLite database files including WAL and shared-memory sidecars, and the UAT staging directory, which holds a cloned database and an encryption key and is deliberately kept out of git so that material never enters history.

    The encryption key is generated at runtime into a 0600 file beside the database rather than being shipped, embedded, or held in an environment variable -- which also keeps it out of process listings and inherited environments. Provider API keys are supplied by the operator at runtime and stored encrypted with AES-256-GCM; none are distributed with the software.

    Test fixtures use obviously non-functional placeholder values, and where a test needs key material it is generated at test time rather than committed.

    The project also treats credentials on the command line as a leak risk in their own right, not just credentials in files: passing a secret as a command-line argument is avoided because it is visible in the process table and can be recorded in shell and tooling history. Secrets are passed by environment variable or stdin instead.

    CI reinforces this -- gosec is among the 23 enabled linters and flags hardcoded credential patterns, and CodeQL analyses every pull request.


 Análise 8/8 ●

  • Análise estática de código


    Pelo menos uma ferramenta de análise estática de código (além de avisos do compilador e modos de linguagem "seguros") DEVE ser aplicada a qualquer grande lançamento de produção proposto do software antes de seu lançamento, se houver pelo menos uma ferramenta FLOSS que implemente este critério na linguagem selecionada. [static_analysis]
    Uma ferramenta de análise estática de código examina o código de software (como código-fonte, código intermediário ou executável) sem executá-lo com entradas específicas. Para fins deste critério, avisos do compilador e modos de linguagem "seguros" não contam como ferramentas de análise estática de código (estes tipicamente evitam análise profunda porque a velocidade é vital). Algumas ferramentas de análise estática focam na detecção de defeitos genéricos, outras focam em encontrar tipos específicos de defeitos (como vulnerabilidades), e algumas fazem uma combinação. Exemplos de tais ferramentas de análise estática de código incluem cppcheck (C, C++), clang static analyzer (C, C++), SpotBugs (Java), FindBugs (Java) (incluindo FindSecurityBugs), PMD (Java), Brakeman (Ruby on Rails), lintr (R), goodpractice (R), Coverity Quality Analyzer, SonarQube, Codacy e HP Enterprise Fortify Static Code Analyzer. Listas maiores de ferramentas podem ser encontradas em lugares como a lista da Wikipedia de ferramentas para análise estática de código, informações da OWASP sobre análise estática de código, lista do NIST de analisadores de segurança de código-fonte e lista de ferramentas de análise estática de Wheeler. Se não houver ferramentas de análise estática FLOSS disponíveis para a(s) linguagem(ns) de implementação usada(s), você pode selecionar 'N/A'.

    Multiple FLOSS static analysis tools run on every change, so every release is analysed by construction rather than as a pre-release step someone has to remember.

    CodeQL (MIT-licensed CLI) is the primary one. It runs on every push and every pull request, plus a weekly scheduled scan, analysing two languages: go for the application itself and actions for the GitHub Actions workflows -- the latter catching workflow-level issues such as untrusted input reaching a run step. Findings surface as code-scanning alerts on the pull request that introduced them, and there are currently zero open alerts. https://github.com/sydlexius/stillwater/blob/main/.github/workflows/codeql.yml

    Alongside it, and also on every change:

    • gosec, the Go security-focused analyser, among the 23 linters enabled via golangci-lint (GPL-3.0)
    • staticcheck, which performs deep interprocedural analysis well beyond compiler diagnostics
    • govulncheck (BSD-3-Clause), which is call-path aware rather than version-range based: it reports a known vulnerability only when the affected code is actually reachable from this project
    • gocritic with its style and performance analysis bundles enabled
    • Hadolint for the Dockerfiles, actionlint for workflow syntax, stylelint for CSS

    These are required status checks, so a finding blocks the change rather than being filed for later. Because they gate every merge, the state of the default branch at any tag is analysis-clean -- a release cannot contain code that has not passed them.

    Beyond static analysis, the project runs mutation testing in CI against its own test suite, checking that the tests actually detect changed behaviour rather than merely executing the lines.

    Current result: golangci-lint run ./... reports 0 issues across the module, and OpenSSF Scorecard independently scores the project 10/10 on its SAST check.



    É SUGERIDO que pelo menos uma das ferramentas de análise estática usadas para o critério static_analysis inclua regras ou abordagens para procurar vulnerabilidades comuns na linguagem ou ambiente analisado. [static_analysis_common_vulnerabilities]
    Ferramentas de análise estática que são especificamente projetadas para procurar vulnerabilidades comuns são mais propensas a encontrá-las. Dito isso, usar quaisquer ferramentas estáticas normalmente ajudará a encontrar alguns problemas, então estamos sugerindo mas não exigindo isso para o nível de selo 'passing'.

    Three of the static analysis tools in use are specifically designed to find vulnerabilities rather than general defects.

    CodeQL runs on every push and pull request with its security query suites for Go, covering the injection, path traversal, SSRF, insecure randomness, and sensitive-data-exposure classes among others. It also analyses the GitHub Actions workflows as a separate language, which catches supply-chain issues such as untrusted input reaching a run step -- a class general-purpose linters do not look for at all. There are currently zero open code-scanning alerts. https://github.com/sydlexius/stillwater/blob/main/.github/workflows/codeql.yml

    gosec is the Go ecosystem's dedicated security analyser, and its rule set maps directly onto the common vulnerability classes: hardcoded credentials, SQL injection, command injection, path traversal, weak or deprecated cryptographic primitives, insecure random number generation, unsafe file permissions, and unhandled errors in security-relevant positions. It is enabled among the 23 linters that run on every change.

    gosec's value here is demonstrable rather than theoretical. Its G404 rule -- non-cryptographic random number generator -- is what forces every use of math/rand in this codebase to be justified in writing: the two non-security uses that exist (a filesystem probe filename and retry jitter) each carry an inline suppression naming the rule and stating why it does not apply. A new math/rand call in a security path would fail the build.

    govulncheck completes the set from a different angle: rather than pattern-matching source, it checks the dependency graph against the Go vulnerability database and reports a known CVE only when the affected function is actually reachable from this project's call paths. That distinction is load-bearing -- one advisory currently affecting a transitive dependency was determined unreachable here by exactly that analysis, rather than by comparing version ranges.

    Supporting these, staticcheck performs deep interprocedural analysis, Hadolint checks the Dockerfiles for insecure container practices, and actionlint validates the workflows.

    OpenSSF Scorecard independently scores the project 10/10 on its SAST check.



    Todas as vulnerabilidades exploráveis de severidade média e superior descobertas com análise estática de código DEVEM ser corrigidas de forma oportuna após serem confirmadas. [static_analysis_fixed]
    Uma vulnerabilidade é considerada de severidade média ou superior se sua pontuação qualitativa base do Common Vulnerability Scoring System (CVSS) for média ou superior. Nas versões 2.0 a 3.1 do CVSS, isso é equivalente a uma pontuação CVSS de 4.0 ou superior. Os projetos podem usar a pontuação CVSS conforme publicada em um banco de dados de vulnerabilidades amplamente usado (como o National Vulnerability Database) usando a versão mais recente do CVSS relatada nesse banco de dados. Os projetos podem, em vez disso, calcular a severidade eles mesmos usando a versão mais recente do CVSS no momento da divulgação da vulnerabilidade, se as entradas de cálculo forem publicamente reveladas uma vez que a vulnerabilidade seja publicamente conhecida. Observe que o critério vulnerabilities_fixed_60_days exige que todas essas vulnerabilidades sejam corrigidas dentro de 60 dias de se tornarem públicas.

    There are currently zero open code-scanning alerts of any severity, verified live against the repository.

    Findings are not allowed to accumulate. Static analysis runs as required status checks on every pull request -- CodeQL, gosec, staticcheck and govulncheck among them -- so a finding blocks the change that introduced it rather than being filed for later triage. A vulnerability therefore cannot reach the default branch and start ageing.

    Where a finding is genuinely a false positive or a deliberate acceptance, it is dismissed with its reasoning recorded rather than silently closed. Of the historical dismissals, all 16 marked "won't fix" and 2 marked "used in tests" carry a written dismissal comment, as do 61 of 62 marked "false positive". The project's standing rule is that a dismissal must state the MECHANISM that makes the finding inapplicable, with file or configuration evidence, never a bare "false positive" -- and that the reasoning is recorded on both surfaces a future reader might consult: the alert itself, and the scanner's inline review thread on the pull request. A dismissal without that reasoning reads, six months later, as someone having waved the finding away.

    The single dismissal missing a comment is a documentation gap in the record rather than an unfixed vulnerability, and the standing rule exists to prevent exactly that.

    Response speed is evidenced elsewhere too: two golang.org/x/crypto advisories surfaced by govulncheck were resolved by upgrading the dependency within hours of being identified, ahead of any external scanner reporting them. One further advisory affecting a transitive dependency has no upstream fix published; call-path analysis confirmed the affected subpackage is never imported here, so it is unreachable rather than outstanding.

    No CVE has been assigned against the project, and no security advisory has been published: https://github.com/sydlexius/stillwater/security



    É SUGERIDO que a análise estática de código-fonte ocorra em cada commit ou pelo menos diariamente. [static_analysis_often]

    Static analysis runs on every commit, not merely daily.

    CodeQL is triggered on every push and every pull request, with an additional weekly scheduled scan so the default branch is re-analysed against updated query packs even when nothing has changed. It analyses two languages: go for the application and actions for the GitHub Actions workflows. https://github.com/sydlexius/stillwater/blob/main/.github/workflows/codeql.yml

    Running alongside it on every change, as required status checks:

    • golangci-lint with 23 linters enabled, including gosec for security-specific rules, staticcheck for deep interprocedural analysis, and gocritic with its style and performance bundles
    • govulncheck against the dependency graph, call-path aware rather than version-range based
    • Hadolint for the Dockerfiles, actionlint for workflow syntax, stylelint for CSS

    Analysis also runs before a commit exists: a pre-commit hook runs golangci-lint over the staged packages, so a finding is caught locally rather than after a push. The gate is real -- a cognitive-complexity violation blocked a commit during recent work and had to be resolved by extracting functions rather than suppressed.

    Because these are required checks on every pull request, and direct commits to the default branch are refused by branch protection, no commit reaches the trunk without having been analysed. The frequency is therefore structural rather than scheduled: there is no window in which unanalysed code can sit on the default branch.

    Recent cadence for scale: 648 commits in the last 90 days, 160 merges to the default branch in the last 30, each analyzed.


  • Análise dinâmica de código


    É SUGERIDO que pelo menos uma ferramenta de análise dinâmica seja aplicada a qualquer grande lançamento de produção proposto do software antes de seu lançamento. [dynamic_analysis]
    Uma ferramenta de análise dinâmica examina o software executando-o com entradas específicas. Por exemplo, o projeto PODE usar uma ferramenta de fuzzing (por exemplo, American Fuzzy Lop) ou um scanner de aplicação web (por exemplo, OWASP ZAP ou w3af). Em alguns casos, o projeto OSS-Fuzz pode estar disposto a aplicar testes de fuzzing ao seu projeto. Para fins deste critério, a ferramenta de análise dinâmica precisa variar as entradas de alguma forma para procurar vários tipos de problemas ou ser um conjunto de testes automatizado com pelo menos 80% de cobertura de ramificação. A página da Wikipedia sobre análise dinâmica e a página da OWASP sobre fuzzing identificam algumas ferramentas de análise dinâmica. A(s) ferramenta(s) de análise PODEM estar focadas em procurar vulnerabilidades de segurança, mas isso não é obrigatório.

    Several dynamic analysis mechanisms run against the software, and each executes it with varying or generated inputs rather than inspecting source.

    FUZZING. 30 native Go fuzz targets across 11 packages, run in CI on a weekly schedule and on demand, each with a time budget. Go's fuzzing engine is coverage-guided: it mutates inputs and retains those that reach new code paths, and any crash or failing input is written to testdata as a permanent regression case, so a discovered defect becomes a standing test rather than a one-off. A crash fails the workflow. The matrix is enforced, so a new fuzz target cannot be added without being exercised. https://github.com/sydlexius/stillwater/blob/main/.github/workflows/fuzz.yml

    END-TO-END API EXERCISE. make bruno-ci builds the binary, starts an ephemeral server, and runs an executable Bruno collection against the live REST API -- a genuine running instance, not a mock.

    ACCESSIBILITY SCANNING. Playwright drives real Chromium and Firefox browsers against rendered pages, with axe-core evaluating the live DOM. This is a browser-driven scan of the running application rather than static template inspection.

    RACE DETECTION. The whole test suite runs under Go's race detector in CI, which is a runtime instrumentation: it observes actual memory access ordering during execution and reports data races that no static pass can see.

    PROVIDER-FAILURE SMOKE TESTS. A dedicated CI tier exercises the application's behaviour when third-party metadata providers fail, so error paths are executed rather than assumed.

    MUTATION TESTING. CI mutates the source and re-runs the suite, checking the tests actually detect changed behaviour. This is a check on the dynamic analysis itself.

    Because these run in CI on every change or on a weekly schedule against the default branch, any tagged release has been dynamically analysed before it is cut, rather than analysis being a step someone must remember at release time.



    É SUGERIDO que se o software produzido pelo projeto incluir software escrito usando uma linguagem insegura em memória (por exemplo, C ou C++), então pelo menos uma ferramenta dinâmica (por exemplo, um fuzzer ou scanner de aplicação web) seja rotineiramente usada em combinação com um mecanismo para detectar problemas de segurança de memória, como estouros de buffer. Se o projeto não produzir software escrito em uma linguagem insegura em memória, escolha "não aplicável" (N/A). [dynamic_analysis_unsafe]
    Exemplos de mecanismos para detectar problemas de segurança de memória incluem Address Sanitizer (ASAN) (disponível no GCC e LLVM), Memory Sanitizer e valgrind. Outras ferramentas potencialmente usadas incluem thread sanitizer e undefined behavior sanitizer. Assertivas generalizadas também funcionariam.

    The project produces no software written in a memory-unsafe language.

    Stillwater is written entirely in Go, which is memory-safe: it is garbage-collected, bounds-checks slice and array access, and does not permit pointer arithmetic. Buffer overwrites and use-after-free of the kind this criterion targets are not expressible.

    There is no C or C++ in the project, and no cgo. Release binaries are built with CGO_ENABLED=0, so the shipped artifacts are pure Go with no linked C libraries at all -- verified in both the release workflow and the goreleaser configuration. Even the SQLite driver is modernc.org/sqlite, a pure-Go transliteration rather than a cgo binding to the C library, which is a deliberate choice that keeps the memory-unsafe surface at zero rather than merely small.

    The browser-facing code is HTML, CSS, and a small amount of vendored JavaScript, none of it memory-unsafe either.

    For completeness, runtime instrumentation is used regardless: the test suite runs under Go's race detector in CI, which is a dynamic memory-access analysis in the same family as ThreadSanitizer -- it observes actual access ordering during execution rather than reasoning about the source. That runs alongside 30 fuzz targets across 11 packages, an executable API collection against a live server, and browser-driven accessibility scanning.



    É SUGERIDO que o projeto use uma configuração para pelo menos alguma análise dinâmica (como testes ou fuzzing) que habilite muitas asserções. Em muitos casos, essas asserções não devem ser habilitadas em builds de produção. [dynamic_analysis_enable_assertions]
    Este critério não sugere habilitar asserções durante a produção; isso é inteiramente decisão do projeto e de seus usuários. O foco deste critério é, em vez disso, melhorar a detecção de falhas durante a análise dinâmica antes da implantação. Habilitar asserções no uso em produção é completamente diferente de habilitar asserções durante a análise dinâmica (como testes). Em alguns casos, habilitar asserções no uso em produção é extremamente imprudente (especialmente em componentes de alta integridade). Existem muitos argumentos contra habilitar asserções em produção, por exemplo, bibliotecas não devem travar chamadores, sua presença pode causar rejeição por lojas de aplicativos e/ou ativar uma asserção em produção pode expor dados privados, como chaves privadas. Observe que em muitas distribuições Linux NDEBUG não é definido, então assert() em C/C++ será habilitado por padrão para produção nesses ambientes. Pode ser importante usar um mecanismo de asserção diferente ou definir NDEBUG para produção nesses ambientes.

    Go has no assert() construct and no NDEBUG-style compile-time toggle, so the C/C++ shape of this criterion does not translate directly. The equivalent -- extra checking enabled during dynamic analysis but not compiled into production builds -- is used extensively.

    RACE DETECTOR. The test suite runs under go test -race in CI, which is exactly this pattern: CGO_ENABLED=1 go test -race instruments every memory access to check ordering at runtime, while release binaries are built with CGO_ENABLED=0 and carry none of that instrumentation. It is a large body of runtime checking that exists only during analysis.

    FUZZING WITH PERSISTED FAILURES. 30 fuzz targets across 11 packages run coverage-guided, and any input that trips a check is written to testdata as a permanent regression case. A crash fails the workflow rather than being reported and forgotten.

    ASSERTIONS AS TEST DISCIPLINE. The project's testing standard requires assertions that most suites omit, and these are the substance of the criterion rather than a syntax question:

    • A test must assert its own PRECONDITIONS, not only its outcome, so a fixture that silently stops exercising the intended path fails instead of passing vacuously. Where a test seeds a directory, it reads the directory back and asserts the count before exercising the code under test.
    • A test guarding a bug fix must be shown to FAIL without the fix -- revert it, confirm red, restore, confirm green -- so a test that asserts nothing meaningful is caught before it lands.
    • Structural assertions are used where a behavioural one cannot see the property: one test parses the source of a function and asserts a statement ordering invariant that no runtime check could observe.

    MUTATION TESTING. CI mutates the source and re-runs the suite, verifying the assertions actually detect changed behaviour rather than merely executing lines.

    None of this instrumentation ships. Production builds are CGO_ENABLED=0, with no race detector, no fuzzing harness, and no test-only checking compiled in.



    Todas as vulnerabilidades exploráveis de severidade média e superior descobertas com análise dinâmica de código DEVEM ser corrigidas em tempo hábil após serem confirmadas. [dynamic_analysis_fixed]
    Se você não está executando análise dinâmica de código e, portanto, não encontrou nenhuma vulnerabilidade dessa forma, escolha "não aplicável" (N/A). Uma vulnerabilidade é considerada de severidade média ou superior se sua pontuação qualitativa base do Common Vulnerability Scoring System (CVSS) for média ou superior. Nas versões 2.0 a 3.1 do CVSS, isso é equivalente a uma pontuação CVSS de 4.0 ou superior. Os projetos podem usar a pontuação CVSS conforme publicada em um banco de dados de vulnerabilidades amplamente utilizado (como o National Vulnerability Database) usando a versão mais recente do CVSS relatada nesse banco de dados. Os projetos podem, em vez disso, calcular a severidade por conta própria usando a versão mais recente do CVSS no momento da divulgação da vulnerabilidade, se as entradas de cálculo forem reveladas publicamente assim que a vulnerabilidade for conhecida publicamente.

    Dynamic analysis is run routinely, and it has not discovered a security vulnerability of medium or higher severity. There is consequently nothing outstanding.

    The mechanisms running are 30 native Go fuzz targets across 11 packages on a weekly schedule, the full test suite under Go's race detector, an executable API collection exercised against a live server, browser-driven accessibility scanning with axe-core, and a provider-failure smoke tier. No fuzz crash, data race, or comparable finding is currently open; a crash fails the fuzzing workflow rather than being reported and forgotten, and any input that trips a check is written to testdata as a permanent regression case.

    What dynamic analysis has found here is correctness defects rather than exploitable vulnerabilities, and those are fixed at the point of discovery rather than deferred. A recent example: a concurrency defect where a cleanup sweep could delete another in-flight operation's staging file, converting a recoverable failure into permanent data loss. It was found during review, fixed in the same session, and the fix was verified by a two-goroutine test that reproduces the loss when the fix is removed -- then re-reviewed rather than trusted. That is a data-integrity bug, not a security vulnerability, but it illustrates the response pattern.

    Verified live against the repository: zero open code-scanning alerts, zero open Dependabot alerts, zero published security advisories, and no CVE assigned. https://github.com/sydlexius/stillwater/security

    If a dynamic analysis run does surface a vulnerability, SECURITY.md commits to an initial acknowledgement within 72 hours and a fix released as soon as practical, typically within 14 days for critical issues. Releases are frequent -- four stable releases in the past month -- so a fix reaches users promptly rather than waiting on a distant release train.



Você pode usar ferramentas e sistemas de IA para propor alterações por meio de uma URL simples, como https://www.bestpractices.dev/pt-BR/projects/14430/choose/edit?osps_ac_01_01_status=Met&osps_ac_01_01_justification=GitHub+enforced. Veja nosso sistema de propostas de automação para saber como fazer isso. Estes dados estão disponíveis sob o Community Data License Agreement – Permissive, Version 2.0 (CDLA-Permissive-2.0). Isso significa que um Destinatário de Dados pode compartilhar os Dados, com ou sem modificações, desde que o Destinatário de Dados disponibilize o texto deste acordo com os Dados compartilhados. Por favor, dê crédito a Jesse Slaton e aos contribuidores do selo de melhores práticas OpenSSF.

Entrada de selo do projeto de propriedade de: Jesse Slaton.
Entrada criada em 2026-09-03 00:15:58 UTC, última atualização em 2026-09-03 01:56:47 UTC.