Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2978,6 +2978,14 @@ Suggestion sidecars use `DataDirectorySecurity.ResolveSensitiveSidecarDirectoryF

Before suggestion text is persisted, typed redaction replaces named credentials, AWS access keys, bearer values, known structured credential formats (including GitHub, Stripe, GitLab, Slack, and OpenAI prefixes), and opaque mixed-character tokens. The high-entropy fallback is identifier-aware: structured PascalCase and snake_case code/test identifiers, including embedded numeric components, leading-underscore identifiers, and slash/hyphen recipe IDs with multiple word boundaries remain available as reproducibility evidence. Single-block or alternating-case opaque tokens and known token formats remain redacted as `[REDACTED:high_entropy_token]`.

The same redactor preserves complete ordinary relative file references such as `artifacts/full-dogfood-20260912/FINDINGS.md#d01` in persistence, show, and JSON/Markdown/issue-draft export (#5345). This additional entropy exception validates spelling only; it never reads a referenced file or establishes that the file exists in the repository. It requires forward slashes, a filename with a 1–8 ASCII-letter extension, at most 260 path characters, at most 16 components, and at most 100 characters per component. Dot, hyphen, and underscore separate nonempty words within components. Words may be lowercase (up to 24 letters), uppercase (up to 12), or camel/Pascal words whose individual parts have 3–24 letters; a word can end with up to four digits, and a standalone numeric part can have up to eight digits for dates. Each component must also pass the sensitive-name check. The Markdown fragment remains separate and subject to normal secret detection.

Known credential and assignment redaction runs before this exception. A preceding-context check of at most 128 characters also excludes values introduced by sensitive names such as case-insensitive `bearer` or `password:`, and declines the exception if that context budget is exhausted. Complete-token boundaries prevent accepting a suffix of an absolute/home path, URL, escaped path, or other token; empty/traversal components, backslashes, queries, controls within the path, and opaque components do not qualify. Paths outside this deliberately narrow subset retain the existing heuristic redaction behavior, as do the #4403/#4751 identifier controls. The 32,768-character input cap and regex-timeout fallback are unchanged. No historical redaction is reversed: an editable local draft can be repaired only by explicitly supplying the original text with `suggestions update <id> --context "<original>" --db <db>`, preserving its ID and updating its revision. Submitted records retain the existing edit restrictions.

Mixed-case word bodies of 16 or more letters additionally require a run of at least three lowercase letters, preserving the existing distinction between readable identifiers and repeated short alternating-case groups.

Quoted credential names and quoted or collection-valued credentials are recognized before the path exception. Single, double, and backtick quotes, escaped characters, and directly concatenated value parts are consumed through a real value boundary. Existing credential markers remain stable under repeated redaction. Collection scanning allows at most 16 nested arrays/objects; malformed, unterminated, or deeper values conservatively consume the remainder of the already bounded field. YAML block, tag, and anchor/alias values after a credential name also consume that remainder; this recognizer does not parse YAML to recover following fields. A linear enclosing-token scan retains quoted or escaped whitespace and rejects URL/rooted-path prefixes before punctuation, with a 128-character prefix limit. Separate quoted JSON values use independent prefixes, while rooted prefixes cannot reset at a comma. Benign quoted evidence values still use the ordinary path checks.

### Deduplication

`SuggestionStore` first checks a normalized SHA256 content hash, then compares the candidate against the most recent suggestions in the same category and language using normalized-token Jaccard similarity. The default fuzzy threshold is `0.85`; `cdidx mcp --suggestion-dedup-threshold`, `CDIDX_SUGGESTION_DEDUP_THRESHOLD`, or `.cdidxrc.json` `suggestion_dedup_threshold` can override it with a value from `0` to `1`. Fuzzy matches are returned as duplicates before GitHub submission and log the matched immutable ID plus score to stderr for auditability.
Expand Down Expand Up @@ -7432,6 +7440,14 @@ suggestion sidecar は `DataDirectorySecurity.ResolveSensitiveSidecarDirectoryFo

提案テキストを永続化する前に、型付き redaction が名前付き credential、AWS access key、bearer 値、GitHub、Stripe、GitLab、Slack、OpenAI の prefix を含む既知の構造化 credential 形式、および不透明な混合文字 token を置換します。high-entropy fallback は識別子を考慮し、複数の単語境界を持つ構造化された PascalCase / snake_case のコード・テスト識別子(埋め込み数値 component を含む)、先頭 underscore 付き識別子、slash / hyphen 形式の recipe ID は再現性の根拠として保持します。一方、単一ブロックまたは大文字・小文字が交互に並ぶ不透明 token と既知の token 形式は、引き続き `[REDACTED:high_entropy_token]` に置換します。

同じ秘匿処理は、`artifacts/full-dogfood-20260912/FINDINGS.md#d01` のような通常の相対ファイル参照を、保存・詳細表示・JSON/Markdown/Issue draft のエクスポートで保持します(#5345)。追加したエントロピー判定の例外は文字列の構成だけを検証し、参照先を読み取ったり、リポジトリ内の実在を確認したりしません。区切りは `/`、ファイル名の拡張子は ASCII 英字1~8文字、パス全体は260文字以内、構成要素は16個以内、各構成要素は100文字以内とします。構成要素内では `.`・`-`・`_` で空でない単語を区切ります。単語は小文字24文字以内、大文字12文字以内、または各部分が3~24文字の camelCase/PascalCase とし、末尾の数字は4桁以内、日付などの数字だけの部分は8桁以内を許容します。各構成要素には機密名の検査も適用します。Markdown のフラグメントは別の文字列として通常の秘密情報検出を受けます。

既知の資格情報と代入値の秘匿処理を、この例外より先に実行します。直前の文脈も最大128文字まで検査し、大文字小文字を問わない `bearer` や `password:` などの機密名に続く値は例外対象外とします。この検査の上限に達した場合も例外を適用しません。文字列の境界を検証することで、絶対パス・ホーム相対パス・URL・エスケープを含むパス・別のトークンの末尾だけを受け入れることを防ぎます。空または親ディレクトリへの移動を表す構成要素、バックスラッシュ、クエリ、パス内の制御文字、不透明な構成要素は例外対象外です。この限定的な条件に合わないパスと #4403/#4751 の識別子には、既存の判定を維持します。入力32,768文字の上限と正規表現タイムアウト時の代替処理も変更しません。過去の伏字を推測で復元することはありません。編集可能なローカル draft は `suggestions update <id> --context "<原文>" --db <db>` で原文を明示した場合だけ修復でき、ID を維持したまま revision を更新します。送信済みレコードの編集制限も維持します。

大文字と小文字が混在する単語の英字部分が16文字以上の場合は、小文字が3文字以上連続する箇所も必要とします。これにより、読みやすい識別子と短い大文字小文字の組が連続する文字列を区別する既存の判定を維持します。

引用符付きの機密名と、引用符・配列・オブジェクトに包まれた資格情報の値は、パスの例外より先に認識します。単一・二重引用符、バッククォート、エスケープ文字、直結した値の断片を、実際の値の区切りまで含めて秘匿します。既存の資格情報マーカーは繰り返し秘匿しても変化しません。配列・オブジェクトの入れ子は16段までとし、不正な区切り、閉じられていない値、上限を超える入れ子では、既に入力上限を適用したフィールドの残りを安全側に秘匿します。機密名に続く YAML のブロック・タグ・アンカー/エイリアス形式の値も、フィールドの残りを秘匿します。YAML を解析して後続フィールドを復元することはありません。周囲のトークンは文字列長に比例する処理で検査し、引用符内やエスケープされた空白を保持したうえで、括弧などの前に続く URL・絶対パスを除外します。接頭部分の上限は128文字です。別々の引用符付き JSON 値は接頭部分を独立して検証し、絶対パスの接頭部分はコンマでリセットしません。機密値ではない引用符付きの証拠参照には通常のパス検証を適用します。

### 重複排除とローカル保持

`SuggestionStore` はまず正規化した SHA256 content hash を確認し、その後、同じ category / language の直近提案と正規化 token の Jaccard 類似度で比較する。fuzzy しきい値の既定は `0.85` で、`cdidx mcp --suggestion-dedup-threshold`、`CDIDX_SUGGESTION_DEDUP_THRESHOLD`、または `.cdidxrc.json` の `suggestion_dedup_threshold` で `0` から `1` の値へ上書きできる。fuzzy match は GitHub 送信前に重複として返され、監査用に一致先の不変 ID と score を stderr に記録する。
Expand Down
4 changes: 4 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,8 @@ Candidate-ordered parallel-index recovery tests must prove that the fatal result
Workspace freshness and git metadata enrichment behavior.
- `DiagnosticRedactorTests.cs`, `SuggestionStoreTests.cs`
Local suggestion JSON storage: opaque/stable-ID allocation and legacy migration, all-editable-field revision conflicts, dedup hashing, submission-finalization races, persistence, corruption recovery, atomic writes. Keep suggestion-redaction cases table-driven with negative fixtures for structured PascalCase, snake_case, leading-underscore, and recipe identifiers plus positive fixtures for opaque mixed-character and known token formats; the persistence case should retain an identifier and redact a secret from the same context.
Evidence-link coverage (#5345) pairs the exact dated Markdown reference and representative source/document paths with credentials inside path components, sensitive names, traversal, rooted/URL/control inputs, and path/component/input bounds on net8/net9. The shared persistence fixture retains both the link and #4403/#4751 identifier while redacting its credential. Existing production-runtime add/update fixtures reopen the store through human/JSON show and JSON/Markdown/issue-draft export, verify that historical markers survive reads, and recover a stable-ID draft only from explicitly supplied original context.
Review regressions include quoted credential keys, long and concatenated quoted values, backticks, escapes, nested/malformed collections, YAML blocks/tags/anchors, repeated-redaction stability, multiple benign JSON evidence values, apostrophes in prose, and URL/absolute-path suffixes behind punctuation or quoted/escaped spaces. Keep complete-value redaction independent of the 128-character evidence-context budget; verify persistence and all full-text CLI exports with these controls.
- `DataDirectorySecurityTests.cs`, `ProgramCliTests.cs` suggestion-sidecar coverage
Shared-temp database routing, owner-only directory/file modes, colocated private-directory behavior, and structured CLI filesystem failures.
Suggestion-history query coverage keeps NFKC/case-insensitive matching across every documented field, structured filters before deterministic pagination, aggregate omission reasons, compact redaction, progressing continuations, and whole-document UTF-8 byte budgets in the same production-runtime fixture.
Expand Down Expand Up @@ -2312,6 +2314,8 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
ワークスペース鮮度と git メタデータ付与のテスト。
- `DiagnosticRedactorTests.cs`、`SuggestionStoreTests.cs`
ローカル提案JSON蓄積: 不透明で安定した ID の割り当てと legacy migration、全編集対象 field の revision conflict、ハッシュ重複排除、submission finalization race、永続化、破損復旧、アトミック書き込み。提案 redaction のケースは table-driven に保ち、構造化された PascalCase、snake_case、先頭 underscore 付き、recipe 形式の識別子を negative fixture、不透明な混合文字列と既知の token 形式を positive fixture として含めてください。永続化ケースでは、同じ context 内の識別子を保持しつつ secret を伏字化することを確認します。
証拠リンクの検証(#5345)では、報告された日付付き Markdown 参照と代表的なソース・文書パスに対し、構成要素内の資格情報、機密名、親ディレクトリへの移動、絶対パス・URL・制御文字、パス・構成要素・入力の上限を net8/net9 で比較します。共有の保存テストでは、リンクと #4403/#4751 の識別子を保持しつつ資格情報を伏字化します。既存の製品ランタイム用の追加・更新テストで、人間向け/JSON の詳細表示と JSON/Markdown/Issue draft のエクスポートから保存先を読み直し、過去の伏字が読み取りだけでは変わらず、明示した原文によってだけ ID を維持した draft を修復できることを確認します。
レビューの回帰テストでは、引用符付きの機密名、長い引用値や連結値、バッククォート、エスケープ、入れ子や不正なコレクション、YAML のブロック・タグ・アンカー、繰り返し秘匿した結果の安定性、機密値ではない複数の JSON 証拠参照、文章中のアポストロフィ、括弧や引用符内・エスケープされた空白に続く URL・絶対パスの末尾を検証します。値全体の秘匿を、証拠の文脈検査の128文字上限から独立させ、保存とすべての全文 CLI エクスポートでも対照ケースを確認してください。
- `DataDirectorySecurityTests.cs`、`ProgramCliTests.cs` の suggestion-sidecar coverage
shared-temp database routing、owner-only の directory / file mode、private directory での隣接配置、structured CLI filesystem failure。
suggestion-history query coverage は、全 documented field の NFKC / case-insensitive 照合、決定的 pagination より先の structured filter、aggregate omission reason、compact redaction、進捗可能な continuation、document 全体の UTF-8 byte budget を同じ production-runtime fixture で維持します。
Expand Down
Loading
Loading