stillwater

本サイトが提示する下記のベストプラクティスを実行するプロジェクトは、Open Source Security Foundation (OpenSSF) バッジを達成したことを自主的に自己認証し、そのことを外部に示すことができます。

ソフトウェアに欠陥や脆弱性がないことを保証する手立てはありません。形式論的な証明ができたとしても、仕様や前提が間違っていると誤動作の可能性があります。また、プロジェクトが健全で、かつ機能的な開発コミュニティであり続けることを保証する手立てもありません。しかし、ベストプラクティスの採用は、プロジェクトの成果の向上に寄与する可能性があります。たとえば、いくつものベストプラクティスがリリース前の複数人によるレビューを定めていますが、それによりレビュー以外では発見困難な技術的脆弱性を見つけるのを助け、同時に異なる企業の開発者間の信頼を築き、さらに交流を続けることに対する意欲を生んでいます。バッジを獲得するには、すべてのMUSTおよびMUST NOT基準を満たさなければなりません。すべてのSHOULD基準も満たさなければなりませんが、正当な理由がある場合は満たさなくても構いません。そしてすべてのSUGGESTED基準も満たさなければなりませんが、満たさないとしても、少なくとも考慮することが望まれます。フィードバックは、 GitHubサイトのissueまたはpull requestとして提示されれば歓迎します。また、議論のためのメールリストも用意されています。

私たちは多言語で情報を提供していますが、翻訳版に矛盾や意味の不一致がある場合は、英語版を正式な記述とします。
これがあなたのプロジェクトなら、あなたのプロジェクトページにあなたのバッジステータスを表示してください!バッジステータスは次のようになります。 プロジェクト 14430 のバッジ レベルは in_progress です バッジステータスの埋め込み方法は次のとおりです。
バッジステータスを表示するには、あなたのプロジェクトのマークダウンファイルに以下を埋め込みます
[![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)」。一重引用符または二重引用符を含めないでください。
    複数の言語がある場合は、コンマを区切り(スペースを入れてもよい)としてリストし、使用頻度の高いものから順に並べます。使用言語が多くある場合は、少なくとも最初の3つの最も多く使われるものをリストアップしてください。言語がない場合(例:ドキュメントだけ、またはテスト専用のプロジェクトの場合)、1文字 " - "を使用します。言語ごとにある大文字・小文字の慣用を踏襲してください(例:「JavaScript」)。
    Common Platform Enumeration(CPE)は、情報技術(IT)システム、ソフトウェア、およびパッケージのための構造化された命名体系です。脆弱性を報告する際に、多くのシステムやデータベースで使用されています。
  • 基本的なプロジェクト ウェブサイトのコンテンツ


    プロジェクトのウェブサイトは、ソフトウェアが何をするのか(何の問題を解決するのか)を簡潔に記述しなければなりません。 [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.



    貢献する方法に関する情報は、貢献プロセス(たとえばプル リクエストが使用されか、など)を説明する必要があります。 (URLが必要です) [contribution]
    別段の記載がない限り、GitHub上のプロジェクトは、(GitHubが提供する)課題管理とプルリクエストを使用することを想定します。この情報は不足しているかもしれません。すなわち、プロジェクトがプルリクエストと課題追跡ツールを使うことか、メーリングリストへの投稿を言及している。(どちら?)

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



    貢献する方法に関する情報は、貢献を受け入れるための要件(たとえば、必要なコーディング標準への参照)を含むべきです。 (URLが必要です) [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、2項型BSD、 3項型BSD、 Apache 2.0 、Less GNU General Public License(LGPL)、および GNU General Public License(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).



    プロジェクトは、結果のライセンスをソースリポジトリの標準的な場所に投稿しなければなりません。 (URLが必要です) [license_location]
    たとえば、LICENSEまたはCOPYINGという名前の最上位ファイルです。ライセンスファイル名の後に ".txt" や ".md" などの拡張子を付けることができます。別の規則は、ライセンスファイルを含むLICENSESという名前のディレクトリを持つことです。これらのファイルは通常、 REUSE仕様で説明されているように、SPDXライセンス識別子とそれに続く適切なファイル拡張子として名前が付けられます。この基準は、ソースリポジトリの要件にすぎないことに注意してください。ソースコード(実行可能ファイル、パッケージ、コンテナなど)から何かを生成するときに、ライセンスファイルを含める必要はありません。たとえば、Comprehensive R Archive Network(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)が含まれている場合、アプリケーション プログラム インターフェイスが含まれます。ライブラリの場合、呼び出すことができる主要なクラス/型とメソッド/関数を文書化します。ウェブ アプリケーションの場合、URLインタフェース(多くの場合、RESTインタフェース)を定義します。コマンドラインインターフェイスの場合は、サポートするパラメータとオプションを文書化します。多くの場合、ドキュメントのほとんどを自動生成すると、ソフトウェアが変更されたときにドキュメントがソフトウェアと同期したままなので、最も良い方法ですが、これは必須ではありません。プロジェクトは、ドキュメンテーションとしてプロジェクト以外の素材へのハイパーテキストリンクを使用してもよいです。ドキュメンテーションは自動的に生成されるかもしれません(実際的に、しばしばこれを行う最良の方法です)。 RESTインタフェースのドキュメントは、Swagger / OpenAPIを使用して生成することができます。コード インタフェースのドキュメントは、 JSDoc (JavaScript)、 ESDoc (JavaScript)、pydoc(Python)、devtools (R)、pkgdown (R)、および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]
    これには、プロジェクトのホームページのURLとバージョン管理リポジトリのURLが「http:」ではなく「https:」で始まる必要があります。Let's Encryptからフリーの証明書を入手できます。プロジェクトは、(例えば) GitHubページ、 GitLabページ、またはSourceForgeプロジェクトページを使ってこの基準を実装してもよいです。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.



    プロジェクトは、議論(提案された変更や問題を含む)のための1つ以上の検索可能なメカニズムを持たなければならず、メッセージやトピックが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]
    少なくとも、プロジェクトは重大な問題と脆弱性の報告に対応するように努める必要があります。バッジを積極的に追求しているプロジェクトは、おそらくメンテナンスされているでしょう。すべてのプロジェクトや人のリソースには限りがあり、提案された変更をプロジェクトが拒否しなければならないこともあるため、リソースに限りがあることや、提案が拒否されることが、メンテナンスされていないプロジェクトを示すわけではありません。

    プロジェクトが今後メンテナンスされなくなることがわかった場合は、この基準を「不適合(Unmet)」に設定し、適切なメカニズムを使用して、メンテナンスされないことを人々に示す必要があります。たとえば、READMEの最初の見出しに「DEPRECATED」(将来のサポートが保証されないので使用すべきでない)を使用し、ホームページの先頭近くに「DEPRECATED」を追加し、コード リポジトリのプロジェクトの説明の先頭に「DEPRECATED」を追加し、そのREADMEおよび/またはホームページにno-maintenance-intendedバッジを追加し、すべてのパッケージ リポジトリでdeprecated(非推奨)としてマークしたり(例: npm deprecate )、コード リポジトリのマーキングシステムを使用してアーカイブします(例:GitHubの"archive" 設定、GitLabの"archived" マーキング、 Gerritの "readonly" ステータス、またはSourceForgeの"abandoned" プロジェクト ステータス)。詳細な説明については、こちらを参照してください。

    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 commit idやmercurial changeset 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.



    リリースには、Semantic Versioning (SemVer)またはCalendar Versioning (CalVer)のバージョン番号形式を使用することが推奨されます。CalVerを使用する場合は、マイクロレベル値を含めることが推奨されます。 [version_semver]
    プロジェクトは一般的に、エコシステムで使用されている通常のフォーマットなど、ユーザーが期待しているフォーマットを優先するべきです。多くのエコシステムではSemVerが好まれており、一般的にSemVerはアプリケーションプログラマインターフェース(API)やソフトウェア開発キット(SDK)に好まれています。CalVerは、規模が大きく、独自に開発した依存関係が異常に多いプロジェクトや、スコープが常に変化するプロジェクト、時間的な制約があるプロジェクトで使用される傾向があります。CalVerを使用する際には、マイクロレベルの値を含めることが推奨されます。マイクロレベルを含めることで、必要になった場合にはいつでも同時にメンテナンスされるブランチをサポートできるからです。git commit ID や mercurial changeset ID など、バージョンを一意に識別できるものであれば、他のバージョン番号形式をバージョン番号として使用することができます。しかし、(git commit ID のような)いくつかの代替形式は、リリースの識別子として問題を引き起こす可能性があります。すべての受信者が最新バージョンを実行しているだけの場合 (たとえば、継続的な配信を介して常に更新されている単一のWebサイトまたはインターネットサービスのコード)には、バージョン ID の形式はソフトウェアのリリースを識別する上で重要ではないかもしれません。


    プロジェクトがバージョン管理システム内の各リリースを特定することが推奨されています。たとえば、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.


  • リリースノート


    プロジェクトは、各リリースにおいて、ユーザーがアップグレードすべきかどうか、また、アップグレードの影響を判断できるよう、そのリリースの主要な変更の要約を説明したリリースノートを提供しなければなりません(MUST)。リリースノートは、バージョン管理ログの生の出力であってはなりません(例えば、 "git log"コマンドの結果はリリースノートではない)。プロジェクトの成果物が複数の場所で再利用されることを意図していないプロジェクト(単独のウェブサイトやサービスのためのソフトウェアなど)で、かつ、継続的・断続的な配布を行う場合は、「該当なし」を選択することができます。 (URLが必要です) [release_notes]
    リリースノートは様々な方法で実装できます(MAY)。多くのプロジェクトは、 "NEWS"、 "CHANGELOG"、または "ChangeLog"という名前のファイルでそれらを提供し、 ".txt"、 ".md"、 ".html"などの拡張子を付けることもあります。歴史的には、 "change log"という言葉はすべての変更のログを意味していましたが、本基準を満たすために必要なものは、人間が読める要約です。リリースノートは代わりに、 GitHubリリースのワークフローなどのバージョン管理システムのメカニズムによって提供してもよい(MAY)。

    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.



    リリースノートでは、このリリースで修正された、リリースの作成時にすでにCVE割り当てなどがあった、公に知られているランタイムの脆弱性をすべて特定する必要があります。 ユーザーが通常、ソフトウェアを実際に更新できない場合(たとえば、カーネルの更新によくあることです)、この基準は該当なし(N/A)としてマークされる場合があります。 この基準はプロジェクトの結果にのみ適用され、依存関係には適用されません。 リリースノートがない場合、または公に知られている脆弱性がない場合は、[N/A]を選択します。 [release_notes_vulns]
    この基準は、特定の更新によって一般に知られている脆弱性が修正されるかどうかをユーザーが判断するのに役立ち、ユーザーが情報に基づいて更新について決定できるようにします。ユーザーが通常、コンピューター上でソフトウェア自体を実際に更新することはできず、代わりに1つ以上の仲介者に依存して更新を実行する必要がある場合(カーネルお​​よびカーネルと絡み合っている下位レベルのソフトウェアの場合によくあることです)、この追加情報はそれらのユーザーには役立たないため、プロジェクトは「該当なし」(N/A)を選択する場合があります。同様に、すべての受信者が最新バージョンのみを実行している場合(継続的デリバリーによって絶えず更新される単一のWebサイトまたはインターネットサービスのコードなど)、プロジェクトは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 ●

  • バグ報告プロセス


    プロジェクトは、ユーザーが不具合報告を送信するプロセスを提供しなければなりません(たとえば、課題トラッカーやメーリングリストを使用します)。 (URLが必要です) [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ヶ月(2ヶ月を含む)に増強要求の多数(> 50%)に対応すべきです。 [enhancement_responses]
    応答は、「いいえ」や、そのメリットについての議論であってもよいです。目標は、単にプロジェクトがまだ生きていることを示している、いくつかの要求に対する応答があることです。この基準のために、プロジェクトは偽のリクエスト(スパマーや自動システムなど)をカウントする必要はありません。プロジェクトで機能強化が行われていない場合は、「満足されない」(unmet)を選択し、この状況をユーザーに明確にするURLを含めてください。プロジェクトが強化要求の数によって圧倒される傾向がある場合は、「満足されない」(unmet)を選択して説明してください。

    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



    プロジェクトは、後で検索するために、レポートとレスポンスのアーカイブを公開する必要があります。 (URLが必要です) [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


  • 脆弱性報告プロセス


    プロジェクトは、脆弱性を報告するプロセスをプロジェクト サイトに公開しなければなりません。 (URLが必要です) [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.



    プライベート脆弱性報告がサポートされている場合、プロジェクトは、プライベートに保持された方法で情報を送信する方法を含んでいなくてはなりません。 (URLが必要です) [vulnerability_report_private]
    例としては、HTTPS(TLS)を使用してWeb上に提出されたプライベート不具合報告や、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、autotools、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として公開されている自動テストスイートを少なくとも1つ使用する必要があります(このテストスイートは、別個のFLOSSプロジェクトとして維持される場合があります)。 プロジェクトは、テストスイートの実行方法を明確に示すか文書化する必要があります(たとえば、継続的インテグレーション(CI)スクリプトを介して、またはBUILD.md、README.md、CONTRIBUTING.mdなどのファイルの文書を介して)。 [test]
    プロジェクトでは、複数の自動化されたテストスイートを使用することができます(たとえば、迅速に実行するもの、より完全であるが特別な装置が必要なもの)。Selenium (ウェブブラウザの自動化)、Junit (JVM, Java)、RUnit (R)、testthat (R) など、多くのテストフレームワークやテスト支援システムが利用可能です。

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

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

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

    THE SUITES:

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

    Every suite is FLOSS and none requires a paid service.

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



    テスト スイートは、その言語の標準的な方法で呼び出すことができるべきです。 [test_invocation]
    たとえば、「make check」、「mvn test」、「rake test」(Ruby)などです。

    The test suite is invoked the standard way for Go:

    go test ./...
    

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

    go test -race ./...
    

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

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



    テスト スイートは、コードブランチ、入力フィールド、および機能のほとんど(または理想的にはすべて)をカバーすることが推奨されています。 [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, 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.


  • 警告フラグ


    プロジェクトは、選択した言語でこの基準を実装することができる少なくとも1つのFLOSSツールがあれば、1つまたは複数のコンパイラ警告フラグ、「安全」言語モードを使用可能にするか、分離 「リンター」ツールを使用してコード品質エラーまたは共通の単純なミスを検索しなければなりません。 [warnings]
    コンパイラ警告フラグの例には、gcc / clang "-Wall"があります。 「安全」言語モードの例には、JavaScript「use strict」とperl5の「use warnings」があります。分離「リンター」ツールは、ソースコードを調べてコード品質のエラーや一般的な単純なミスを探すツールです。これらは、通常、ソースコードまたはビルド命令内で有効になります。

    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]
    これらは、警告基準の実装によって識別される警告です。プロジェクトは、警告を修正するか、ソースコード内で警告を誤検出としてマークするべきです。理想的には警告がないことがいいですが、プロジェクトはある程度の警告(通常は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 ●

  • セキュリティに関する開発知識


    プロジェクトには、安全なソフトウェアを設計する方法を知っている少なくとも1人の主要な開発者が必要です。 (正確な要件については、「詳細」を参照してください。) [know_secure_design]
    これには、Saltzer and Schroeder の8つの原則を含む以下の設計原則を理解する必要があります。
    • メカニズムの経済性(たとえば、スイーピング シンプリフィケーションを採用して、メカニズムを実際的に単純化し小さくする)
    • フェイルセーフのデフォルト(アクセスの決定はデフォルトで拒否されるべきであり、プロジェクトのインストールはデフォルトで安全でなければならない)
    • 完全なメディエーション(制限されたすべてのアクセスは権限がチェックされ、バイパスされない)
    • オープンな設計(セキュリティメカニズムは攻撃者の設計に対する無知に依存するべきではなく、 簡単に保護ができて変更ができる鍵やパスワードのような情報に依存すべきです。
    • 特権の分離(理想的には、重要なオブジェクトへのアクセスは複数の条件に依存すべきで、1つの保護システムを破ることで完全なアクセスが可能にならないようにします。たとえば、パスワードとハードウェア トークンを必要とする多因子認証は単因子認証より強いです。
    • 最低限の権限(プロセスは最低限の権限で動作する必要がある)
    • 最低限の共通メカニズム(設計は、複数のユーザに共通のメカニズムや全てのユーザーに依存するメカニズムを最小限に抑えるべきです。)
    • 心理学的受容性(ヒューマンインタフェースは、使いやすく設計されていなければならない - 「驚きが最小限になる」という設計が助けになる)
    • 限られた攻撃面(攻撃面 - 攻撃者がデータを入力または抽出しようとする部分 - を制限する必要があります)
    • ホワイト リストで入力を検証します(入力は通常、この検証はブラックリスト(既知の不良値をリストする)ではなく、ホワイトリスト(既知の値のみを受け入れる)を使用する必要があります。
    プロジェクトの「主要な開発者」とは、プロジェクトのコードベースに精通していて、容易に変更を加えることができ、プロジェクトの他のほとんどの参加者によって認められている人です。主要な開発者は、通常、過去1年間に(コード、文書、または質問に回答して)多数の貢献を行います。ある開発者が、プロジェクトを開始している(3年以上プロジェクトから離れていない)、プライベート脆弱性報告チャネル(存在する場合)に関する情報を受け取る、プロジェクトを代表してコミットを受け入れる、最終リリースする、などを行う時主要な開発者とみなすことができます。開発者が1人だけの場合、その人物が主要開発者です。より安全なソフトウェアを開発し、設計について議論する方法を理解するのに役立つ多くの本やコースが利用可能です。 たとえば、 Secure Software Development Fundamentals コースは、3つのコースの無料セットです。 より安全なソフトウェアを開発する方法を説明しています。

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



    プロジェクトの主要開発者の少なくとも1人は、この種のソフトウェアの脆弱性につながる一般的な種類のエラーを知っていなければならず、それぞれを対策または緩和する少なくとも1つの方法を知っていなければなりません。 [know_common_errors]
    例(ソフトウェアの種類によって異なります)には、SQLインジェクション、OSインジェクション、従来のバッファオーバーフロー、クロスサイトスクリプティング、認証の欠落、承認の欠落などがあります。一般的に使用されるリストについては、 CWE/SANSトップ25またはOWASPトップ10を参照してください。より安全なソフトウェアを開発する方法を理解し、脆弱性につながる一般的な実装エラーについて説明するのに役立つ多くの書籍やコースが用意されています。たとえば、 Secure Software Development Fundamentalsコースは、より安全なソフトウェアを開発する方法を説明する3つのコースの無料セットです(受講は無料です。追加料金を払うと、学習したことを証明する証明書を入手できます)。

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


  • 優良な暗号手法を使用する

    一部のソフトウェアは暗号化メカニズムを使用する必要がないことに注意してください。あなたのプロジェクトが作成するソフトウェアが、(1) 暗号化機能を含む、アクティブ化する、または有効化し、(2) 米国(US)から米国外または米国市民以外にリリースされる可能性がある場合は、法的に義務付けられた追加手順の実行を要求される可能性があります。通常、これにはメールの送信が含まれます。詳細については、 Understanding Open Source Technology & US Export Controls(「オープンソース技術と米国の輸出管理について」)の暗号化のセクションを参照してください。

    プロジェクトによって作成されたソフトウェアは、デフォルトで、一般に公開され、専門家によってレビューされている暗号プロトコルとアルゴリズムを使用しなければなりません。(暗号プロトコルとアルゴリズムが使用される場合) [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年までのNIST最小要件(2012年)を満たすデフォルト鍵長を使用しなければなりません。より小さな鍵長を完全に無効になるおうに、ソフトウェアを構成できなければなりません。 [crypto_keylength]
    これらの最小ビット長は、対称鍵112、ファクタリング係数2048、離散対数鍵224、離散対数群2048、楕円曲線224、ハッシュ224(パスワードハッシュはこのビット長でカバーされません。パスワードハッシュに関する詳しい情報は crypto_password_storage 基準にあります)です。さまざまな機関が出している推奨鍵長の比較については、https://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など)に依存したり、実装する必要がない限り、コンテキストに不適切な暗号化モードを使用したりしてはなりません。相互運用可能なプロトコル(実装されたプロトコルがネットワークエコシステムによって広くサポートされている標準の最新バージョンであり、そのエコシステムではそのようなアルゴリズムまたはモードの使用が必要であり、そのエコシステムはこれ以上安全な代替手段を提供しません)。これらの壊れたアルゴリズムまたはモードが相互運用可能なプロトコルに必要な場合、ドキュメントには、関連するセキュリティリスクと既知の緩和策を記載する必要があります。 [crypto_working]
    ECBモードは、 ECBペンギンによって示されるように暗号文内の同一のブロックを明らかにするため、ほとんど適切ではありません。また、CTRモードは、認証を実行せず、入力状態が繰り返されると重複を引き起こすため、不適切なことがよくあります。多くの場合、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]
    SSHのCBCモードに関する懸念事項は、 CERT: 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.



    プロジェクトによって作成されたソフトウェア内のセキュリティ メカニズムは、鍵合意プロトコルのための完全な順方向秘密を実装するべきなので、もし長期鍵が将来侵害された場合でも、長期鍵のセットから導出されるセッション鍵は侵害されません。 [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.



    プロジェクトによって作成されたソフトウェアが外部ユーザーの認証用のパスワードの保存を引き起こす場合、パスワードは、キーストレッチ(反復)アルゴリズム(Argon2id、Bcrypt、Scrypt、PBKDF2など)を使用して、ユーザーごとのソルトで反復ハッシュとして保存される必要があります。OWASP Password Storage Cheat Sheetも参照してください)。 [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.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(man-in-the-middle:中間者)攻撃に対応できる安全な配信


    プロジェクトは、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



    暗号ハッシュ(たとえばSHA1SUM)は、http経由で運んではならず、暗号署名をチェックすることなしに使用してはいけません。 [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(共通脆弱性識別子)を持つとき(例えば、 National Vulnerability Database )、またはプロジェクトに情報が伝えられ、その情報が(おそらくプロジェクトによって)一般に公開されたとき、脆弱性は一般に知られるようになります。Common Vulnerability Scoring System (CVSS)の定性的スコアが中程度以上であれば、脆弱性は中程度以上の深刻度とみなされます。CVSS のバージョン 2.0 から 3.1 では、これは CVSS のスコア 4.0 以上に相当します。プロジェクトは、広く利用されている脆弱性データベース(国家脆弱性データベースなど)で公開されているCVSSスコアを、そのデータベースで報告されている最新バージョンのCVSSを用いて使用することができます。代わりに、プロジェクトは、脆弱性が公表された時点で計算入力内容が公開されている場合には、脆弱性が公表された時点でのCVSSの最新版を用いて深刻度を計算することができます。注意:これは、ユーザーが最大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ツールが少なくとも1つある場合、少なくとも1つの静的コード分析ツール(コンパイラの警告と「安全な」言語モード以外)を、ソフトウェアの主要な製品リリースの提案に、リリース前に適用する必要があります。 [static_analysis]
    静的コード解析ツールは、ソフトウェアコードを実行せずに特定の入力を用いて(ソースコード、中間コード、または実行可能ファイルとして)調べます。この基準のために、コンパイラの警告と「安全な」言語モードは、静的コード解析ツールとしてカウントされません(これらは通常、速度が重要なため深い解析を行いません)。このような静的コード解析ツールの例には、cppcheck (C, C++)、clang静的解析 (C, C++)、SpotBugs (Java)、FindBugs (Java) (FindSecurityBugsを含む)、PMD (Java)、Brakeman (Ruby on Rails)、lintr (R)、goodpractice (R), Coverity Quality Analyzer、SonarQube、 Codacyおよび HP Enterprise Fortify Static Code Analyzer.大きなツールのリストは、静的コード解析のためのWikipediaツール一覧, 静的コード解析に関するOWASP情報、 NISTソースコードセキュリティアナライザのリスト、およびウィーラーの静的解析ツール一覧などがあります。 使用する実装言語で使用できる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基準に使用される静的解析ツールの少なくとも1つが、分析された言語または環境における共通の脆弱性を探すためのルールまたはアプローチを含むことが、推奨されています。 [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]
    Common Vulnerability Scoring System (CVSS)の基本的な定性的なスコアが中程度以上であれば、脆弱性は中程度以上の深刻度とみなされます。CVSS のバージョン 2.0 から 3.1 では、これは CVSS のスコア 4.0 以上に相当します。プロジェクトは、広く利用されている脆弱性データベース(国家脆弱性データベースなど)で公開されているCVSSスコアを、そのデータベースで報告されている最新バージョンのCVSSを用いて使用することができます。また、脆弱性が公開された時点で計算入力が公開されている場合には、脆弱性が公開された時点でのCVSSの最新バージョンを用いて深刻度を計算することもできます。基準 vulnerabilities_fixed_60_days では、公開後 60 日以内にすべての脆弱性を修正することが要求されていることに注意してください。

    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.


  • 動的コード分析


    リリース前に、ソフトウェアの主要な製品リリースに少なくとも1つの動的解析ツールを適用することが示唆されています。 [dynamic_analysis]
    動的解析ツールは、ソフトウェアを特定の入力で実行して検査します。たとえば、プロジェクトは、ファジングツール(アメリカンファジーロップなど)やウェブ アプリケーション スキャナ(例: ZAP または w3af )です。場合によっては、 OSS-Fuzz プロジェクトがプロジェクトにファズテストを適用する可能性があります。この基準のために、動的分析ツールは、様々な種類の問題を探すために何らかの方法で入力を変更するかまたは少なくとも80%のブランチ カバレッジを持つ自動テスト スイートである必要があります。 動的解析に関するWikipediaのページと ファジングに関するOWASPページで、いくつかの動的解析ツールを特定しています。解析ツールは、セキュリティの脆弱性を探すことに重点を置くことができますが、これは必須ではありません。

    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 ++など)を使用して作成されたソフトウェアが含まれている場合、少なくとも1つの動的ツール(たとえば、ファジーまたはウェブ アプリケーション スキャナ)を、バッファの上書きなどのメモリの安全性の問題を検出するメカニズムと一緒にいつも使用します。プロジェクトがメモリ安全でない言語で書かれたソフトウェアを作成しない場合は、「該当なし」(N/A)を選択します。 [dynamic_analysis_unsafe]
    メモリの安全性の問題を検出するメカニズムの例としては、アドレスサニタイザー(ASAN)(GCCおよびLLVMで利用可能)、 Memory Sanitizer 、および valgrind が含まれます。他に使用される可能性のあるツールには、スレッドサニタイザと定義されていない動作サニタイザを参照してください。広範なアサーションも機能します。

    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]
    動的コード分析を実行しておらず、この方法で脆弱性が見つからない場合は、「該当なし」(N/A)を選択してください。 Common Vulnerability Scoring System (CVSS)の基本的な定性的スコアが中以上の場合、脆弱性は中程度以上の重大度と見なされます。 CVSSバージョン2.0から3.1では、これは4.0以上のCVSSスコアに相当します。プロジェクトは、広く使用されている脆弱性データベース( National Vulnerability Databaseなど)で公開されているCVSSスコアを、そのデータベースで報告されている最新バージョンのCVSSを使用して使用できます。代わりに、脆弱性が公表された後に計算入力が公開された場合、プロジェクトは脆弱性の開示時に最新バージョンのCVSSを使用して重大度を自ら計算することができます。

    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システムを使って、https://www.bestpractices.dev/ja/projects/14430/choose/edit?osps_ac_01_01_status=Met&osps_ac_01_01_justification=GitHub+enforcedのような簡単なURLで変更を提案できます。その方法については、自動化提案システムをご覧ください。 このデータは、Community Data License Agreement – Permissive, Version 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