


Goサーバーに、セキュリティを弱めずにモジュールを足す
機能を足していけるGoサーバーで、機能を作る時やレビューする時に使う。モジュールを作る所から片付けまでの順で書かせ、設定ファイルを厳しく読み取り、Linux・macOS・Windowsでテスト・リンター・ビルドを通してからマージし、プルリクエストは人に任せる。
このAIルールを使うには
## 安全な初期設定を守り、新しい機能を置く場所を決める
インターネットに公開されるサーバープラットフォームでは、安全なデフォルトを最優先の製品要件として扱います。
機能をコアに密結合させず、組み合わせ可能なモジュールとして設計します。
1つのデプロイだけを対象とするパッチより、同種のユースケース全体に役立つ汎用的な拡張を優先します。
変更がトップレベルアプリケーション、再利用可能なモジュール、設定の適応処理、コマンドラインのエントリーポイントのどこに属するかを特定します。
個別に開発されたコンポーネントが衝突しないよう、モジュール識別子の名前空間を維持します。
人が扱いやすいアダプターを利用できる場合でも、ネイティブの構造化設定モデルを維持します。
リクエスト処理、トランスポートセキュリティ、ID、証明書管理、信頼境界を特に厳しくレビューします。
担当箇所が分散している場合は、関連するリポジトリやパッケージ全体でセキュリティ上重要な動作を追跡します。
影響を受ける信頼境界と障害モードを理解するまで、セキュリティ上重大な変更をマージ可能とみなしてはいけません。
同梱コンポーネントを発見・監査できるよう、標準モジュールレジストリを明示的に保ちます。
偶発的な登録に依存せず、コマンドバイナリが意図したモジュール一式をインポートするようにします。
新機能を複数の層に合理的に配置できる場合は、アーキテクチャ上の配置を文書化します。
実装の手間を減らすためだけに安全なデフォルトを弱める設計は却下します。
最初の設計判断から、サポート対象の各OSとの互換性を考慮します。
## エラー・名前・コメントを、Goのふつうの書き方で書く
エラーには早期リターンを使い、成功時の処理を最も浅いインデントに保ちます。
すでにreturnする分岐の後にelse分岐を置かないようにします。
URL、HTTP、IDなど、一般的な頭字語は慣例どおりすべて大文字で記述します。
レシーバーの型を一貫して表す短いレシーバー名を選びます。
エラー文字列は小文字で始め、末尾に句読点を付けません。
エクスポートする要素のドキュメントは、宣言名から始まる完全な文として記述します。
確保済みの空スライスに意味上の価値がない場合は、nilスライスを使います。
想定される失敗にはpanicではなくエラーを返します。
失敗する可能性のある操作の近くでエラーを処理します。
追加の文脈が失敗した操作の特定に役立つ場合に限り、エラーをラップします。
プログラムからの処理を想定する場合は、呼び出し側が検査できる形式でエラーを保持します。
リソースの所有権やクリーンアップを分かりにくくする巧妙な制御フローは避けます。
レビュー前にフォーマットと静的解析を実行します。
別のGoスタイルも妥当な場合でも、リポジトリで確立された規約に従います。
フレームワークのインターフェースを満たすことが期待される型には、コンパイル時インターフェース表明を使います。
意図的な互換性変更が承認されない限り、レシーバー名、パッケージ名、エクスポート名を安定させます。
## モジュールを、作る所から片付けまでの順で作る
各モジュールをフレームワークの標準登録機構で登録します。
名前空間付きモジュールIDと、新しいインスタンスを生成するコンストラクターを含むメタデータを返します。
コンストラクターに環境固有の副作用を持たせないようにします。
ライフサイクルを次の順序付きフェーズとして扱います。
1. 新しい値を構築します。
2. その値に設定をデコードします。
3. ランタイム依存要素をプロビジョニングします。
4. 完成した設定を検証します。
5. モジュールの機能を提供または実行します。
6. 所有するリソースをクリーンアップします。
設定とプロビジョニングのデータが揃う前に最終検証を実行してはいけません。
フレームワークがそのように呼び出す可能性がある場合は、部分的なプロビジョニング後や停止シグナルの反復後でもクリーンアップを安全にします。
プロビジョニング、検証、設定解析、その他の任意インターフェースにはコンパイル時ガードを使います。
設定エラーと実行時障害を区別できるよう、ライフサイクル上の責務を分離します。
プロビジョニングと検証では、対処につながるエラーを返します。
初期化の失敗を、部分的に使用できるモジュールの背後に隠してはいけません。
開始と停止の動作を本当に所有するコンポーネントだけに、トップレベルアプリケーションのインターフェースを使います。
設定、アダプター、外部連携が依存する可能性があるため、モジュールIDを安定させます。
## 設定ファイルを厳しく読み取り、管理用エンドポイントを守る
人が記述する設定は、フレームワークのトークンディスペンサーまたは同等の構造化イテレーターで解析します。
行内引数を読む前に、ディレクティブ名を消費します。
行内引数とネストされたブロックを別々に処理します。
現在のネストレベルを記録し、パーサーがそのブロックを離れた時点で停止します。
サポート対象のサブディレクティブを明示的に認識します。
必須引数を直ちに検証し、パーサー標準の引数エラーを返します。
未知のサブディレクティブは、予期しない値を含むエラーで拒否します。
受け付ける構文を、保守対象の契約としてパーサーの近くに文書化します。
アダプターの出力をネイティブの構造化設定モデルと一致させます。
プロビジョニング中に、フレームワークコンテキストを通じてロガーや他のモジュールを取得します。
モジュール単位の構造化ロガーを使い、非構造化メッセージを組み立てる代わりにフィールドを付加します。
リクエストコンテキストやプロビジョニングコンテキストを長寿命の構造体に保存してはいけません。
管理用エンドポイントを追加する場合は、フレームワークのルーティングインターフェースを実装します。
管理インターフェースに求められる認証、認可、公開範囲の規則を適用します。
モジュールがトラフィックの処理を開始する前に設定を検証します。
## 新しい依存関係を増やさず、パッケージの境界を守る
価値が保守、セキュリティ、サプライチェーンのコストを明確に上回らない限り、新しい依存関係は避けます。
小さな依存関係が不釣り合いなリスクを加える場合は、小規模で安定した機能をインラインで実装します。
外部パッケージの型をプロジェクトの公開APIに露出させてはいけません。
サードパーティの動作を、プロジェクトが所有するインターフェースと型の背後にラップします。
言語のモジュールツールを使い、依存関係の宣言とチェックサムの整合性を保ちます。
依存関係を整理するコマンドを実行し、無関係な変更を受け入れずにそのdiffをレビューします。
設定アダプターをランタイムモジュールから分離します。
テスト用ユーティリティを本番のエントリーポイントから分離します。
標準モジュールを、同梱コマンドが使用するレジストリに配置します。
明示的な製品判断なしに、任意モジュールをデフォルトバイナリへインポートしてはいけません。
プロトコル処理、トランスポートセキュリティ、証明書操作を囲むパッケージ境界を維持します。
対象となる反復動作を特定した後でのみ、汎用化された抽象化を選びます。
単純な実装を分かりにくくする推測的な抽象化は却下します。
リファクタリング時は、観測可能な動作を維持するか、意図した変更をすべて文書化してテストします。
セキュリティ上重要なパッケージと依存関係の変更は、通常の内部コードより深くレビューします。
## マージの前に、テスト・リンター・ビルドを全部通す
必須の品質ゲートはすべて、参考事項ではなくブロッキング条件として扱います。
競合検出を有効にして、完全なshortテストスイートを実行します。
リポジトリ全体を完了できる十分な時間を確保し、設定済みのリンターを実行します。
すべてのパッケージをビルドし、インターフェースの欠落、プラットフォーム制約、登録エラーを検出します。
性能変更では、メモリ計測を有効にしたベンチマークを実行します。
ベンチマーク結果を適切なベースラインと比較し、ばらつきを考慮します。
影響を受けるサーバー動作について、対象を絞った統合テストを実行します。
CIがそれらのプラットフォームをサポートする場合は、Linux、macOS、Windowsですべてのテストが通るようにします。
他の場所に無関係な警告が存在しても、変更したファイル内の警告を調べます。
必須のテスト、リンター、ビルド、ベンチマークのいずれかのゲートが欠けている間は、プルリクエストをマージ可能とみなしてはいけません。
レビュー担当者が証拠を再現できるよう、コマンドと関連結果を記録します。
本番コードを変更する前に、テストの失敗と環境の失敗を区別します。
直接影響を受けるすべてのゲートを網羅しながら、変更に見合う範囲で検証します。
レビュー対応でコードを変更した後は、影響を受けるゲートを再実行します。
競合レポートと不安定な並行処理の失敗を、調査が必要な欠陥として扱います。
## テーブル駆動の単体テストと、ポートを分けたサーバーテストを書く
複数の入力が同じ動作を共有する場合は、テーブル駆動テストを優先します。
各ケースに、明示的な入力、期待する出力、期待するエラー状態を指定します。
期待するエラーがない場合と、予期しないエラーが返った場合の両方を確認します。
エラー条件を適切に処理してから、返された値を比較します。
正常、無効、境界、回帰の各ケースを含めます。
インデックスだけでは失敗の診断が難しい場合は、ケースに名前を付けます。
フィクスチャを最小限かつ決定的に保ちます。
エンドツーエンドの設定動作には、プロジェクトのサーバーテストハーネスを使います。
分離された設定と明示的な形式でテストサーバーを初期化します。
ローカルで実行中のサービスとの衝突を避けるため、非標準ポートを使います。
必要に応じて、管理、平文トラフィック、暗号化トラフィックに別々のポートを確保します。
ステータス、本文、その他の外部から観測できる動作を表明します。
テストが作成したサーバー、リスナー、ファイル、ゴルーチンをクリーンアップします。
テストの実行順序や共有された可変グローバル状態に依存してはいけません。
サーバーの正常起動だけでなく、設定解析エラーもテストします。
パス、ソケット、シグナル、プロセス動作が異なる場合は、プラットフォーム固有のケースを追加します。
失敗によって壊れた契約を特定できる程度に、統合テストの対象を絞ります。
## プルリクエスト・セキュリティ報告・契約への同意は人に任せる
イシューでの議論、プルリクエスト、ライセンス契約、セキュリティ報告を、人間が統制する外部アクションとして扱います。
AIアシスタントは、人間の貢献者になりすましたり、本人に代わって法的契約に同意したりしてはいけません。
統制ポリシーがそのエージェントの操作を明示的に許可していない限り、外部のイシュー、プルリクエスト、セキュリティ報告を作成または送信してはいけません。
レビュー支援を許可された役割の範囲に限定し、必要な場合はAIの関与を明示します。
貢献ポリシーで開示が求められる場合、AIの関与を隠してはいけません。
提出するすべての行について、人間の担当者が理解し説明できることを必須とします。
AI支援コードは、可能な場合は自動チェックで、それ以外は綿密な手動チェックでテストします。
生成コードに、コピーされた素材、非互換ライセンス、未検証の主張がないかレビューします。
脆弱性の詳細を捏造したり、未検証のセキュリティ報告を提出したりしてはいけません。
翻訳または編集の支援では、人間の著者が確認したセキュリティ上の事実を維持しなければなりません。
人間だけが行う署名、証明、貢献者契約は、責任を負う本人に委ねます。
要求された操作が貢献ポリシーと競合する場合は、その操作を中止し、適用される境界を説明します。
禁止された外部アクションの代わりとして、欺瞞的なファイル、コメント、コミットを追加してはいけません。
コミュニティのプロセスを迂回せず、パッチの技術的有用性を維持します。
承認前に、開示、理解、テスト、ライセンスをそれぞれ独立したゲートとして検証します。
エージェントが実装の大半を生成した場合でも、人間の説明責任は引き続き必要です。
