stillwater

遵循以下最佳实践的项目将能够自愿的自我认证,并显示他们已经实现了核心基础设施计划(OpenSSF)徽章。

没有一套可以保证软件永远不会有缺陷或漏洞的做法;如果规范或假设是错误的,即使合适的方法也可能失败。也没有哪些做法可以保证一个项目能够维持健康和运作良好的开发者社区。但是,遵循最佳做法可以帮助改善项目的成果。例如,一些做法可以在发布之前进行多人评估,这可以帮助您找到其他难以找到的技术漏洞,并帮助建立信任,并希望不同公司的开发人员之间进行重复的交互。要获得徽章,必须满足所有“必须”和“禁止”的条款,满足所有“应该”条款或有合适的理由,和所有“建议”条款必须满足或未满足(至少希望考虑)。欢迎通过 GitHub网站创建问题或提出请求进行反馈。另外还有一个一般讨论邮件列表。

如果这是您的项目,请在您的项目页面上显示您的徽章状态!徽章状态如下所示: 项目14430的徽章级别为in_progress 这里是如何嵌入它:
您可以通过将其嵌入在您的Markdown文件中:
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/14430/badge)](https://www.bestpractices.dev/projects/14430)
或将其嵌入到HTML中来显示您的徽章状态:
<a href="https://www.bestpractices.dev/projects/14430"><img src="https://www.bestpractices.dev/projects/14430/badge"></a>


这些是通过级别条款。您还可以查看白银或黄金级别条款。

Baseline Series: 基准等级1 基准等级2 基准等级3

        

 基本 13/13 ●

  • 常规

    请注意,其他项目可能使用相同的名称。

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

    请使用 SPDX许可证表达格式;例子包括“Apache-2.0”,“BSD-2-Clause”,“BSD-3-Clause”,“GPL-2.0+”,“LGPL-3.0 +”,“MIT”和“(BSD-2-Clause OR Ruby)”。
    如果有多种语言,请将它们列为逗号分隔值(可选空格),并将它们从最多到最少使用。如果有长列表,请至少列出前三个最常见的列表。如果没有语言(例如,这是仅文档或仅测试项目),请使用单个字符“ - ”。请使用每种语言的常规大小写,例如“JavaScript”。
    通用平台枚举(CPE)是用于信息技术系统,软件和软件包的结构化命名方案。在报告漏洞时,它可用于多个系统和数据库。
  • 基本项目网站内容


    项目网站必须简明扼要地描述软件的作用(它解决了什么问题?)。 [description_good]
    必须采用潜在用户可以理解的语言(例如,它使用最少的术语/行话)。

    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.



    项目网站必须提供有关如何获取和提供反馈(错误报告或增强功能)以及如何贡献的信息。 [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.



    关于如何贡献的信息必须解释贡献流程(例如,是否使用拉请求?) (需要网址) [contribution]
    除非另有说明,否则我们假定 GitHub上的项目使用问题列表(Issues)和拉(Pull)请求。这些信息可以简短,例如,说明项目使用拉请求,问题跟踪器或邮寄到邮件列表中的哪一个。

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



    关于如何贡献的信息应包括对可接受的贡献的要求(例如,引用任何所需的编码标准)。 (需要网址) [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.


  • FLOSS许可证


    项目生产的软件必须作为FLOSS发布。 [floss_license]
    FLOSS是以符合开源定义或免费软件定义。此类许可证的示例包括 CC0 , MIT , BSD 2条款, BSD 3条款修订版, Apache 2.0 , Lesser GNU通用公共许可证(LGPL),以及 GNU通用公共许可证(GPL)。为了我们的目的,这意味着许可证必须是:该软件也可以用其他许可证(例如,“GPLv2或专有”是可以接受的)。

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



    建议由项目生成的软件的任何必需的许可证是由开放源码促进会(OSI)批准的许可证(英文)。 [floss_license_osi]
    OSI (开放源代码促进会)使用严格的审批流程来确定哪些许可证是开源软件(OSS)。

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



    项目必须将其许可证在其源代码存储库中的标准位置发布。 (需要网址) [license_location]
    一种约定是将许可证发布为名为LICENSE或COPYING的顶级文件,其后可以带有扩展名,例如“ .txt”或“ .md”。另一种约定是使用一个名为LICENSES的目录,其中包含许可证文件。这些文件通常被命名为其SPDX许可证标识符,后跟适当的文件扩展名,如REUSE Specification中所述。请注意,此标准只是源存储库上的要求。从源代码生成某些内容(例如可执行文件,程序包或容器)时,无需包括许可证文件。例如,在为综合R存档网络(CRAN)生成R软件包时,请遵循标准CRAN惯例:如果许可证是标准许可证,请使用标准简短许可证规范(以避免安装另一文本副本)并列出排除文件(例如.Rbuildignore)中的LICENSE文件。同样,在创建Debian软件包时,您可以在版权文件中放置一个指向/ usr / share / common-licenses中的许可证文本的链接,并从创建的软件包中排除许可证文件(例如,通过在调用dh_auto_install之后删除文件) )。我们鼓励在可行的情况下以生成的格式包含机器可读的许可证信息。

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


  • 文档


    项目必须为项目生成的软件提供基本文档。 [documentation_basics]
    该文档必须在某些媒体(例如文本或视频)中,包括:如何安装它,如何启动它,如何使用它(可能使用教程使用示例)以及如何安全地使用它(例如,做什么和不做什么),如果这是软件的一个适当的话题。安全文档不需要太长篇幅。项目可以使用非项目内容的超文本链接作为文档。如果项目不生产软件,请选择“不适用”(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.



    项目必须提供描述项目生成的软件的外部接口(输入和输出)的参考文档。 [documentation_interface]
    外部接口的文档向最终用户或开发人员解释如何使用它。这将包括其应用程序接口(API),如果软件有。如果它是一个库,记录可以调用的主要类/类型和方法/函数。如果是Web应用程序,定义其URL接口(通常是其REST接口)。如果是命令行界面,请记录其支持的参数和选项。在许多情况下,最好是自动生成大部分文档,以便本文档随着软件的更改而保持同步,但这并不是必需的。项目可以使用非项目材料的超文本链接作为文档。文档可以自动生成(实际上这通常是最好的方法)。可以使用Swagger / OpenAPI生成REST接口的文档。代码界面文档可以使用 JSDoc (JavaScript), ESDoc (JavaScript),pydoc(Python)和Doxygen(很多)。仅在实现代码中添加注释不足以满足本条款;在没有阅读所有源代码的情况下,需要一个简单的方法来查看信息。如果项目不生产软件,请选择“不适用”(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.


  • 其他


    项目网站(网站,存储库和下载URL)必须使用TLS支持HTTPS。 [sites_https]
    您可以从Let's Encrypt获取免费证书。项目可以使用(例如) GitHub页面实现此条款, GitLab页面,或 SourceForge项目页面。如果您使用具有自定义域的GitHub页面,则可以使用内容传送网络(CDN)作为代理来支持HTTPS,例如博客文章“使用CloudFlare安全加速GitHub页面”,以满足此条款。如果您支持HTTP,我们敦促您将HTTP流量重定向到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.



    该项目必须有一个或多个讨论机制(包括建议的更改和问题),可搜索,允许通过URL访问消息和主题,使新人能够参与一些讨论,并且不需要客户端安装专有软件。 [discussion]
    可接受机制的示例包括归档邮件列表,GitHub问题和拉请求讨论,Bugzilla,Mantis和Trac。如果满足这些标准,异步讨论机制(如IRC)是可以接受的;确保有一个URL可访问归档机制。允许专有JavaScript,但不鼓励。

    GitHub supports discussions on issues and pull requests.



    项目应该提供英文文档,并能够接受英文的代码的错误报告和评论。 [english]
    英语是计算机技术的通用语言;支持英语增加了全球不同潜在开发者和检视者的数量。即使核心开发人员的主要语言不是英文,项目也可以达到这个标准。

    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.



    必须维护该项目。 [maintained]
    至少,项目应尝试响应重大问题和漏洞报告。可能正在维护一个积极追求徽章的项目。所有项目和人员的资源都有限,典型项目必须拒绝某些提议的更改,因此有限的资源和提议拒绝本身并不表示未维护的项目。

    当项目知道将不再维护该项目时,应将此标准设置为“未满足”,并使用适当的机制向其他人指示该项目将不会得到维护。例如,使用“ DEPRECATED”作为其自述文件的第一个标题,在其主页开头附近添加“ DEPRECATED”,在其代码存储库项目说明的开头添加“ DEPRECATED”,在其中添加无需维护的标志其自述文件和/或主页,在任何软件包存储库中将其标记为已弃用(例如npm deprecate ),和/或使用代码存储库的标记系统对其进行归档(例如GitHub的“ archive”设置,GitLab的“ archived”标记, Gerrit的“只读”状态,或SourceForge的“已放弃”项目状态)。可以在这里找到更多讨论。

    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


 变更控制 9/9 ●

  • 公开的版本控制的源代码存储库


    该项目必须有一个版本控制的源代码存储库。它必须是公开可读的并可通过URL访问。 [repo_public]
    该URL可以与项目URL相同。该项目可能在特定情况下使用私人(非公开)分支,而更改不会公开发布(例如,在向公众披露漏洞之前修复漏洞)。

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



    项目的源代码存储库必须跟踪所做的更改,谁进行了更改,何时进行了更改。 [repo_track]

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



    为了实现协作检视,项目的源代码存储库必须包括临时版本,以便检视版本之间的变化;它不得仅包括最终版本。 [repo_interim]
    项目可以选择从其公共源代码库中删除特定的临时版本(例如,修复特定的未公开安全漏洞,可能永远不会公开发布的内容,或者包括不能合法发布而且不是最终版本的内容)。

    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



    建议使用通用分布式版本控制软件(例如,git)作为项目的源代码存储库。 [repo_distributed]
    Git不是必须,项目在合适场景可以使用集中版本控制软件(如subversion)。

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


  • 唯一版本编号


    项目生成的用于每个用户使用的版本必须具有唯一版本标识符。 [version_unique]
    本条款可以通过各种方式来满足,包括提交ID(例如git提交ID或者Mercurial 更改列表id)或版本号(包括使用语义版本或基于日期的方案,如YYYYMMDD的版本号)。

    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.



    建议使用语义版本控制(SemVer)格式进行发布。 [version_semver]
    其他版本编号方案,如提交ID(例如git commit id或mercurial changeset id)或基于日期的方案,如YYYYMMDD,可以用作版本号,因为它们是唯一的。一些备选方案可能会导致问题,因为用户可能无法轻松确定是否是最新的。如果所有目标客户仅运行最新版本,则SemVer可能不太有助于识别软件版本(例如,它是通过持续交付不断更新的单个网站或互联网服务的代码)。


    建议项目识别其版本控制系统中的每个版本。例如,建议使用git的项目,使用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.


  • 发行说明


    该项目必须在每个版本中提供发布说明,这是该版本中主要变化的可读的摘要,以帮助用户确定是否应升级,升级影响将如何。发行说明不能是版本控制日志的原始输出(例如,“git log”命令结果不是发行说明)。其产出不适用于多个地点的项目(如单个网站或服务的软件),并采用持续交付,可以选择“N/A”。 (需要网址) [release_notes]
    发行说明可以以各种方式实施。许多项目将它们添加到名为“NEWS”,“CHANGELOG”或“ChangeLog”的文件中,可选的包含“.txt”,“.md”或“.html”等扩展名。历史上,术语“更改日志”是指每个更改的日志,但为了满足这些条款,需要的是可读取的摘要。发行说明可以由版本控制系统机制提供,例如 GitHub发布工作流程。

    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.



    发行说明必须列出每个新版本中修复的每个公开的漏洞。如果没有发行说明或者没有公开的漏洞,选择“不适用”。 [release_notes_vulns]
    如果用户通常不能在自己的计算机上实际更新软件,而必须依靠中间人来执行升级(对于内核和与内核交织的底层软件通常是这种情况),项目可以选择“不适用”(N/A)。

    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.


 报告 8/8 ●

  • 错误报告流程


    项目必须为用户提交错误报告(例如,使用问题跟踪器或邮件列表)提供相关流程。 (需要网址) [report_process]

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



    项目必须使用问题跟踪器来跟踪每个问题。 [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



    该项目必须响应过去2-12个月内(含)提交的大多数错误报告;响应不需要包括修复。 [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



    该项目应该对过去2-12个月内(包括)的大部分(> 50%)的增强请求作出回应。 [enhancement_responses]
    答复可能是“不”或有关其价值的讨论。目的只是对某些请求有一些回应,这表明项目还活着。为了该条款的目的,项目不需要计数无效请求(例如,来自垃圾邮件发送者或自动系统)。如果项目不再进行增强,请选择“未满足”,并将介绍此情况的URL包含在内。如果一个项目有超出处理能力的增强需求数量,请选择“未满足”并解释。

    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



    该项目必须有一个公开的报告和回复的档案供后续搜索。 (需要网址) [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


  • 漏洞报告流程


    项目必须在项目网站上发布报告漏洞的流程。 (需要网址) [vulnerability_report_process]
    例如,https://PROJECTSITE/security 上的一个明确指定的邮箱地址,通常以 security@example.org 的形式。这可能与其错误报告流程相同。漏洞报告可能一直是公开的,但是许多项目都有一个私密漏洞报告机制。

    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.



    如果支持私有漏洞报告,项目必须包括如何以保密的方式发送信息。 (需要网址) [vulnerability_report_private]
    示例包括使用HTTPS(TLS)或使用OpenPGP加密的电子邮件在网络上提交的私密缺陷报告。如果漏洞报告总是公开的(从来没有私密漏洞报告),请选择“不适用”(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.



    该项目在过去6个月收到的任何漏洞报告的初始响应时间必须小于或等于14天。 [vulnerability_report_response]
    如果过去6个月没有报告漏洞,请选择“不适用”(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


 质量 13/13 ●

  • 可工作的构建系统


    如果项目生成的软件需要构建使用,项目必须提供可以从源代码自动重新构建软件的可工作的构建系统。 [build]
    构建系统确定重建软件(以及以什么顺序)需要执行哪些操作,然后执行这些步骤。例如,它可以调用编译器来编译源代码。如果从源代码创建可执行文件,则必须可以修改项目的源代码,然后通过这些修改生成更新的可执行文件。如果项目生成的软件取决于外部库,则构建系统不必构建那些外部库。如果在修改源代码之后不需要构建任何使用该软件的软件,请选择“不适用”(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



    建议使用通用工具来构建软件。 [build_common_tools]
    例如,Maven,Ant,cmake,自动工具,make,rake(Ruby)或devtools (R)。

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



    该项目应该仅使用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


  • 自动测试套件


    该项目必须使用至少一个作为FLOSS公开发布的自动测试套件(该测试套件可以作为单独的FLOSS项目维护)。 [test]
    该项目可以使用多个自动测试套件(例如,一个是快速运行的测试套件,而另一个更为彻底但需要特殊设备)。

    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.



    测试套件应该以该语言的标准方式进行调用。 [test_invocation]
    例如“make check”,“mvn test”或“rake test”。

    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.



    建议测试套件覆盖大部分(或理想情况下所有)代码分支,输入字段和功能。 [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



    建议项目实施持续集成,将新的或更改的代码经常集成到中央代码库中,并对结果进行自动化测试。 [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


  • 新功能测试


    该项目必须有通用的策略(正式或非正式),当主要的新功能被添加到项目生成的软件中,该功能的测试应该同时添加到自动测试套件。 [test_policy]
    只要有相应的策略,即使是通过口头传播,也就是说开发人员应该为主要的新功能在自动化测试套件中添加测试,选择“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.



    该项目必须有证据表明,在项目生成的软件的最近重大变化中,已经遵守了添加测试的条款: test_policy 。 [tests_are_added]
    主要功能通常在发行说明中提及。不需要完美,只需证明,当新的主要功能添加到项目生成的软件时,测试通常会在实践中被添加到自动化测试套件中。

    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.



    建议您在更改提案的说明文档中添加测试策略要求(请参阅test_policy)。 [tests_documented_added]
    但是,只要在实践中添加了测试,即使是非正式规则也是可以接受的。

    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.


  • 警告标志


    该项目必须启用一个或多个编译器警告标志,“安全”语言模式,或者使用单独的“linter”工具查找代码质量错误或常见的简单错误,如果至少有一个FLOSS工具可以在所选择的语言实现此条款。 [warnings]
    编译器警告标志的例子包括gcc/clang “-Wall”。 “安全”语言模式的示例包括JavaScript “use strict”和perl5的“使用警告”。一个单独的“linter”工具用于检查源代码以查找代码质量错误或常见的简单错误。这些通常在源代码或构建指令中启用。

    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



    该项目必须处理警告。 [warnings_fixed]
    告警是通过执行warnings条款确定的。该项目应该修复告警或在源代码中将其标记为误报。理想情况下,不会有告警,但项目可能会接受一些告警(通常每100行小于1个告警,或整体少于10个告警)。

    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



    建议在实际情况下,项目以最严格方式对待项目生成的软件中的告警。 [warnings_strict]
    某些项目无法有效启用某些警告。需要证明的是,项目正在努力的启用警告标志,以便早期发现错误。

    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


 安全 14/16 ●

  • 安全开发知识


    该项目必须至少有一个主要开发人员知道如何设计安全软件。 [know_secure_design]
    这需要了解以下设计原则,包括 Saltzer和Schroeder 中的8项原则:
    • 机制经济(保持设计简单实用,例如采用彻底简化)
    • 故障安全默认(默认情况下,访问决策应拒绝),项目安装应默认安全)
    • 完全仲裁(必须检查每个可能被限制的访问权限,并且不可绕过)
    • 开放式设计(安全机制不应该依赖于攻击者对其设计的无知,而应该更容易地保护和更改信息,例如密钥和密码)
    • 特权分离(理想情况下,对重要对象的访问应该取决于多个条件,从而破坏一个保护系统将无法实现完全访问。如,多因子身份验证,要求密码和硬件令牌,比单因子认证安全性更高)
    • 最小权限(进程应该以最少的权限运行)
    • 最少的公共机制(设计应该最大限度地减少所有用户所依赖的,涉及到多个用户的共同机制,如,临时文件的目录)
    • 心理可接受性(人机接口必须设计为易于使用 —— 设计为“最不惊讶”)
    • 有限的攻击面(攻击面 —— 一组不同的入口,其​​中攻击者可以尝试输入或提取数据 —— 应该受到限制)
    • 输入验证与白名单(输入通常应该在被接受之前检查以确定是否有效;此验证应使用白名单(仅接受已知的有效值),而不是黑名单(尝试列出已知的非法值))。
    项目中的“主要开发人员”的定义是熟悉项目代码的任何人,很乐意对其进行更改,并被项目中大多数其他参与者确认。主要开发人员通常会在过去一年中通过代码,文档或回答问题提供一些贡献。开发人员通常被认为是主要开发人员,如果他们启动项目(并且还没有离开项目满三年),可以选择在私人漏洞报告渠道(如果有的话)上接收信息,可以代表项目接受提交,或执行项目软件的最终版本发布。如果只有一个开发者,那个人是主要开发人员。

    ...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.



    该项目的主要开发人员中,至少有一个必须知道导致这类型软件漏洞的常见错误类型,以及至少有一种方法来对付或缓解这些漏洞。 [know_common_errors]
    示例(取决于软件的类型)包括SQL注入,操作系统注入,经典缓冲区溢出,跨站点脚本(XSS),缺少认证和缺少授权。请参阅 CWE/SANS 25种最常见漏洞或 OWASP十大漏洞类型项目。

    ...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.


  • 使用基础的良好加密实践

    请注意,某些软件不需要使用加密机制。

    项目生成的软件默认情况下,只能使用由专家公开发布和审查的加密协议和算法(如果使用加密协议和算法)。 [crypto_published]
    这些加密条款并不总是适用,因为某些软件不需要直接使用加密功能。

    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.



    如果项目生成的软件是应用程序或库,其主要目的不是实现加密,那么它应该只调用专门设计实现加密功能的软件,而不应该重新实现自己的。 [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.



    项目所产生的软件中,所有依赖于密码学的功能必须使用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



    项目生成的软件中的安全机制使用的默认密钥长度必须至少达到2030年(如2012年所述)的NIST最低要求。必须提供配置,以使较小的密钥长度被完全禁用。 [crypto_keylength]
    这些最小位长度是:对称密钥112,因式分解模数2048,离散对数密钥224,离散对数组2048,椭圆曲线224和散列224(密码散列不涉及该位长度),关于密码散列的更多信息可以在 crypto_password_storage 条款)。请参阅 http://www.keylength.com 以比较不同组织的密钥长度建议。在某些配置中,软件可能允许较小的密钥长度(理想情况下不会,因为这允许降级攻击,但是互操作性有时需要较短的密钥长度)。

    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.



    项目产生的软件中的默认安全机制不得取决于已被破解的密码算法(例如,MD4,MD5,单DES,RC4,Dual_EC_DRBG)或使用不适合上下文的密码模式(例如,ECB模式几乎不适当,因为它揭示了密文中相同的块,如 ECB企鹅所示。CTR模式通常是不合适的,因为如果重复输入状态,则它不执行认证并导致重复)。 [crypto_working]
    在许多情况下,最好选择设计用于组合保密和认证的块密码算法模式,例如Galois / Counter Mode(GCM)和EAX。项目可以允许用户为必要的兼容性启用已被破解的加密机制,但是需要用户知道他们正在这么做。

    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.



    由项目产生的软件中的默认安全机制不应该依赖于具有已知严重弱点的加密算法或模式(例如,SHA-1密码散列算法或SSH中的CBC模式)。 [crypto_weaknesses]
    在 CERT:SSH CBC漏洞中讨论了SSH中CBC模式的问题。

    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.



    项目产生的软件中的安全机制应该​​对密钥协商协议实施完美的前向保密(PFS),如果长期密钥集合中的一个长期密钥在将来泄露,也不能破坏从一组长期密钥导出的会话密钥。 [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.



    如果项目产生的软件存储用于外部用户认证的密码,则必须使用密钥拉伸(迭代)算法(例如,PBKDF2,Bcrypt或Scrypt)将密码存储为每用户盐值不同的迭代散列 。 [crypto_password_storage]
    此条款仅适用于软件强制使用密码验证用户身份的情况(如服务器端Web应用程序)。在软件存储用于认证到其他系统的密码(例如,该软件实现某个其他系统的客户端)的情况下,这是不适用的,因为该软件的至少某个部分必须经常访问未散列加密的密码。

    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.



    由项目生成的软件中的安全机制必须使用密码学安全的随机数生成器生成所有加密密钥和随机数,并且不得使用密码学不安全的生成器。 [crypto_random]
    密码安全的随机数生成器可以是硬件随机数生成器,或者它可以是使用诸如Hash_DRBG,HMAC_DRBG,CTR_DRBG,Yarrow或Fortuna之类的算法的加密安全的伪随机数生成器(CSPRNG)。对安全性随机数生成器的调用示例包括Java的java.security.SecureRandom和JavaScript的window.crypto.getRandomValues。调用不安全随机数生成器的示例包括Java的java.util.Random和JavaScript的Math.random。

    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.


  • 安全交付防御中间人(MITM)的攻击


    该项目必须使用一种针对MITM攻击的传递机制。使用https或ssh + scp是可以接受的。 [delivery_mitm]
    一个更强大的机制是使用数字签名的软件包发布软件,因为这样可以减轻对分发系统的攻击,但只有在用户确信签名的公钥是否正确的情况下才可以确定。用户实际上会检查签名。

    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



    不得通过http协议获取加密散列(例如,sha1sum)并直接使用,而不检查密码学签名。 [delivery_unsigned]
    这些散列可以在传输过程中修改。

    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.


  • 修正公开的漏洞


    被公开了超过60天的中等或更高严重程度的漏洞,必须被修复。 [vulnerabilities_fixed_60_days]
    该漏洞必须由项目本身修补和发布(修补程序可能在其他地方开发)。一旦漏洞具有公开发布的非付费信息的CVE(例如,在国家漏洞数据库)或项目已被通知,且信息已经发布给公众(可能是项目自己发布),则视为漏洞已经公众所知。如果其 CVSS 2.0 基本分数为4或更高,则漏洞是中等到高的严重性。 注意:这意味着全世界的所有攻击者可能会对用户造成长达60天的伤害。这个标准通常比Google在重新启动负责任的披露中所推荐的容易得多。因为Google建议,如果报告不是公开的,那么当项目得到通知,甚至报告尚未公开时,60天的时间段就会开始。

    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



    项目在得到报告后应该迅速修复所有致命漏洞。 [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.


  • 其他安全问题


    公共存储库不得泄漏旨在限制公众访问的有效私人凭证(例如,工作密码或私钥)。 [no_leaked_credentials]
    项目可以泄漏测试和不重要数据库的“样本”凭据,只要它们不旨在限制公共访问。

    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.


 分析 8/8 ●

  • 静态代码分析


    如果至少有一个FLOSS工具以所选择的语言实现此条款,则至少需要将一个静态代码分析工具应用于软件发布之前任何提议的主要生成版本。 [static_analysis]
    静态代码分析工具检查软件代码(源代码,中间代码或可执行文件),而不用特定输入执行。本条款中,编译器警告和“安全”语言模式不被视为静态代码分析工具(它们通常避免深入分析,因为速度至关重要)。此类静态代码分析工具的示例包括 cppcheck , clang静态分析器, FindBugs (包括FindSecurityBugs), PMD , Brakeman , Coverity质量分析器和 HP Fortify静态代码分析器。更多的工具列表可以在诸如维基百科静态代码分析工具列表,关于静态代码分析的OWASP信息, NIST源代码安全分析器列表和 Wheeler的静态分析工具列表。 SWAMP 是使用各种工具评估软件漏洞的免费平台。如果没有可用于所使用的实现语言的FLOSS静态分析工具,请选择“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.



    建议至少有一个用于static_analysis标准的静态分析工具包括在分析语言或环境中查找常见漏洞的规则或方法。 [static_analysis_common_vulnerabilities]
    专门设计用于寻找常见漏洞的静态分析工具更有可能找到它们。也就是说,使用任何静态工具通常会帮助找到一些问题,所以我们“通过”级别的徽章建议,但不要求这个条款。

    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.



    使用静态代码分析发现的所有中,高严重性可利用漏洞必须在确认后及时修复。 [static_analysis_fixed]
    如果其 CVSS 2.0 评分为4或更高,则此漏洞是中等到高的严重性。

    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



    建议每次提交或至少每天执行静态源代码分析。 [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.


  • 动态代码分析


    建议在发布之前,至少将一个动态分析工具应用于软件任何发布的主要生产版本。 [dynamic_analysis]
    动态分析工具通过执行特定输入来检查软件。例如,项目可以使用模糊工具(例如, American Fuzzy Lop )或Web应用扫描程序(例如, ZAP 或 w3af )。在某些情况下, OSS-Fuzz 项目可以对您的项目应用模糊测试。为满足此条款,动态分析工具需要以某种方式改变输入,以寻找各种问题,或者将其作为一个具有至少80%分支覆盖率的自动测试套件。 动态分析维基百科页面和 OWASP的fuzzing页面 识别一些动态分析工具。分析工具可能专注于寻找安全漏洞,但这不是必需的。

    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.



    建议如果项目生成的软件包含使用内存不安全语言编写的软件(例如C或C++),则至少有一个动态工具(例如,fuzzer或web应用扫描程序)与检测缓冲区覆盖等内存安全问题的机制例行应用。如果该项目生成的软件没有以内存不安全语言编写,请选择“不适用”(N / A)。 [dynamic_analysis_unsafe]
    检测内存安全问题的机制的示例包括AddressSanitizer(ASAN)(可在GCC和LLVM中使用),“Memory Sanitizer”和 valgrind 。其他可能使用的工具包括ThreadSanitizer和UndefinedBehaviorSanitizer。广泛的断言也将起作用。

    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.



    建议由项目生成的软件包括许多运行时断言,在动态分析期间检查。 [dynamic_analysis_enable_assertions]
    这个标准并不建议使生产过程中的断言;这完全取决于项目及其用户的决定。该标准的重点是在部署之前的动态分析过程中改善故障检测。在生产使用中启用断言与在动态分析(例如测试)期间启用断言完全不同。在某些情况下,在生产中使用断言是极其不明智的(尤其是在高完整性组件中)。存在许多反对在生产环境中启用断言的论点,例如,库不应使调用程序崩溃,它们的存在可能会导致应用商店拒绝,和/或在生产环境中激活断言可能会暴露诸如私钥之类的私有数据。请注意,在许多Linux发行版中都未定义NDEBUG ,因此C / C ++缺省情况下,assert()将在这些环境中启用生产。对于那些环境中的生产,使用不同的断言机制或定义NDEBUG可能很重要。

    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.



    通过动态代码分析发现的所有严重性为中,高的可利用漏洞必须在确认后及时修复。 [dynamic_analysis_fixed]
    如果 CVSS 2.0 基本分数为4,那么一个漏洞是中等到高的严重性。如果您没有运行动态代码分析,没有发现任何这样的漏洞,选择“不适用”(N/A)。

    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.



您可以使用工具和AI系统通过简单的URL提交变更建议,例如 https://www.bestpractices.dev/zh-CN/projects/14430/choose/edit?osps_ac_01_01_status=Met&osps_ac_01_01_justification=GitHub+enforced。请参阅我们的自动化提案系统,了解具体操作方法。 该数据可在社区数据许可协议 – 许可性,版本 2.0 (CDLA-Permissive-2.0)下获取。这意味着数据接收方可以共享数据,无论是否经过修改,只要数据接收方在共享数据时提供本协议文本。请注明Jesse Slaton和OpenSSF最佳实践徽章贡献者。

项目徽章条目拥有者: Jesse Slaton.
最后更新于 2026-09-03 00:15:58 UTC, 最后更新于 2026-09-03 01:56:47 UTC。