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
2 changes: 2 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ For background log or metrics sinks, use explicit writer-entry/release signals a
- When command, subcommand, or flag metadata changes, assert that every accepted primary flag appears in shell completions and in command help when the shared parser is authoritative. Dedicated or nested parsers must instead prove their exact usage syntax is complete and does not emit a misleading partial parent-command option list; nested command families still use the shared catalog, and optional-subcommand families retain parent flag candidates alongside nested verbs.
- Immediate help-routing tests must assert both rendered usage and exit code, use a nested command whose normal execution would require additional input so the test proves help does not dispatch it, accept supported public aliases, and reject internal usage keys.
- For JSON output, parse it with `JsonDocument` instead of asserting raw strings.
- Detailed database-diff coverage must keep record materialization within the requested JSON budget plus at most one candidate record, stop only at complete UTF-8 record boundaries, reject cursors after the deterministic difference sequence changes, and withhold continuations that cannot advance. Assert recovery guidance for zero-limit and first-record-too-large pages, suppress unusable cursor/replay metadata in embedded import dry-run comparisons, and preserve valid `--offset` continuation for non-detailed JSON and detailed text output.
- Keep the `files` / `map` `--exclude-tests` cross-command invariant in one seeded fixture: compare `map.file_count` with the parsed `files` row count for both the implicit production-source preset and an explicit `--path`.
- JSON failure-contract tests must assert that stdout contains one parseable versioned error object, stderr is empty, the documented exit code is preserved, and `status` / `error_code` identify the failure.
- Auth-token recipe ranking coverage must pair high-signal credential fixtures with comment, regex-definition, and structural `CancellationToken` / syntax-token decoys, then assert explicit top-N precision for the bearer/authorization, GitHub/API/access-token, and token-secret child queries.
Expand Down Expand Up @@ -1744,6 +1745,7 @@ background の log / metrics sink は、sleep や狭い stopwatch 閾値では
- command、subcommand、flag metadata を変更した場合は、受理される全 primary flag が shell completion に現れ、共有 parser が正本の場合は command help にも現れることを検証する。専用 parser / nested parser では代わりに、正確な usage 構文が完全で、誤解を招く不完全な親 command の option 一覧を出さないことを証明し、nested command family が共有 catalog を使い、optional-subcommand family では nested verb と親 command の flag 候補を併せて維持することも確認する。
- immediate help routing の test は rendered usage と終了コードを併せて検証し、通常実行なら追加入力を必要とする nested command を含めて help が dispatch しないことを証明し、対応する公開 alias の受理と内部 usage key の拒否も確認する。
- JSON 出力は生文字列比較ではなく `JsonDocument` で解析して検証する。
- 詳細 database diff の coverage では、record の materialize を指定 JSON budget と最大 1 件の candidate record 以内に抑え、完全な UTF-8 record 境界でのみ停止し、deterministic な差分 sequence が変化した後の cursor を拒否し、前進できない continuation を返さないことを維持する。limit 0 と最初の record が大きすぎる page の recovery 案内、埋め込み import dry-run 比較で利用不能な cursor / replay metadata を抑止することに加え、非詳細 JSON と詳細 text 出力で有効な `--offset` continuation を検証する。
- `files` / `map` の `--exclude-tests` に関する cross-command invariant は、1 つの seed 済み fixture で維持する。暗黙の本番ソース preset と明示的な `--path` の両方について、`map.file_count` と parse 済み `files` row 数を比較する。
- JSON failure contract のテストでは、stdout に parse 可能な version 付き error object が 1 件だけあること、stderr が空であること、documented exit code が維持されること、`status` / `error_code` が失敗を識別することを検証する。
- auth-token recipe の ranking coverage では、高 signal な credential fixture と comment、regex 定義、構造的な `CancellationToken` / syntax-token decoy を対にし、bearer / authorization、GitHub / API / access-token、token-secret の各 child query について明示的な top-N precision を検証する。
Expand Down
60 changes: 46 additions & 14 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,18 +507,34 @@ use the sibling project directory; other database paths fall back to the process
current directory. `--dry-run` and its `--check` alias also compare an existing
destination DB with the validated archive without replacing it. JSON
`destination_delta.comparison` reports schema and count deltas plus bounded
file, symbol, reference-edge, chunk, and metadata samples. Use
`--limit <n<=10000>` and `--offset <n>` to page those samples. If the destination
does not exist or cannot be read, `destination_delta` reports that state instead
of claiming a comparison.
file, symbol, reference-edge, chunk, and metadata records. Text fields in those
records are represented by named SHA-256 and UTF-8 byte-length metadata rather
than source content or paths. Use `--limit <n<=10000>` and `--offset <n>` to
page those records. If the destination does not exist or cannot be read,
`destination_delta` reports that state instead of claiming a comparison.

Use `cdidx diff <db1> <db2> --detailed --json` to verify the restored index.
Database identity is based on semantic index content: reference-line links are
compared by their indexed path, line, and context rather than SQLite surrogate
row IDs, so equivalent databases remain identical after rows are rehydrated.
Detailed JSON also includes `references_only_in_left/right` and
`chunks_only_in_left/right`. `--limit` bounds each difference family and
`--offset` selects the page; `has_more` and `next_offset` indicate continuation.
Detailed JSON returns one deterministic `records` sequence. Each record names
its `area` and `side`, carries a stable `identity_sha256`, and exposes named
`fields` instead of an opaque encoded row. By default, text fields and database
paths are redacted to SHA-256 and UTF-8 byte-length metadata; source text is
returned only when `--include-content` is explicitly combined with
`--detailed --json`.

Detailed JSON is capped at 1 MiB by default. Every JSON mode accepts
`--max-json-bytes <n>` (4096 through 16777216) for a caller-controlled
whole-output UTF-8 budget. In detailed mode, CodeIndex stops only at complete
record boundaries, so the result remains valid JSON. `total_count`, `returned_count`,
`omitted_count`, `truncated`, and `truncation_reason` describe the page.
`--limit` bounds the unified record page, `--offset` remains available for
direct paging, and `next_cursor` plus `replay.next_page_arguments` provide the
preferred deterministic continuation contract. Reuse the same database
arguments and emitted replay flags to resume. Cursors bind the complete
deterministic difference sequence as well as the database arguments and content
policy; if either database changes, restart without `--cursor`.

## Flag compatibility and migrations

Expand Down Expand Up @@ -3722,17 +3738,33 @@ SQLite file が CodeIndex DB であることを検証してから destination da
それ以外の database path では process current directory に fallback します。
`--dry-run` と alias の `--check` は置換せず、既存 destination DB と検証済み archive を
比較します。JSON の `destination_delta.comparison` には schema / count delta と、
file、symbol、reference edge、chunk、metadata の bounded sample が含まれます。
sample の paging には `--limit <n<=10000>` と `--offset <n>` を使います。destination が
存在しない、または読み取れない場合は、比較済みとせずその状態を `destination_delta` に返します。
file、symbol、reference edge、chunk、metadata の bounded record が含まれます。
これらの record の text field は source content や path そのものではなく、名前付きの
SHA-256 と UTF-8 byte length metadata として表現されます。record の paging には
`--limit <n<=10000>` と `--offset <n>` を使います。destination が存在しない、または
読み取れない場合は、比較済みとせずその状態を `destination_delta` に返します。

復元した index の確認には `cdidx diff <db1> <db2> --detailed --json` を使います。
database の同一性は semantic index content に基づきます。reference-line link は SQLite の
surrogate row ID ではなく indexed path、line、context で比較されるため、row が再構築されても
意味的に同等な database は identical のままです。詳細 JSON には
`references_only_in_left/right` と `chunks_only_in_left/right` も含まれます。
`--limit` は difference family ごとの件数を制限し、`--offset` は page を選択します。
続きがある場合は `has_more` と `next_offset` を返します。
意味的に同等な database は identical のままです。詳細 JSON は deterministic な単一の
`records` sequence を返します。各 record は `area` と `side` を明示し、stable な
`identity_sha256` と、opaque な encoded row ではなく名前付きの `fields` を持ちます。
既定では text field と database path を SHA-256 と UTF-8 byte length metadata に
redact します。source text を返すには `--detailed --json` とともに
`--include-content` を明示的に指定してください。

詳細 JSON は既定で 1 MiB に制限されます。すべての JSON mode で、caller が output
全体の UTF-8 budget を指定するための `--max-json-bytes <n>`(4096 以上 16777216 以下)
を使えます。詳細 mode では CodeIndex が complete record の境界でのみ停止するため、
結果は常に valid JSON です。
page の状態は `total_count`、`returned_count`、`omitted_count`、`truncated`、
`truncation_reason` で確認できます。`--limit` は unified record page を制限し、
direct paging 用の `--offset` も引き続き使えます。deterministic な続きの取得には
`next_cursor` と `replay.next_page_arguments` を使うことを推奨します。同じ database
arguments と、出力された replay flags を再利用して再開してください。cursor は database
arguments と content policy に加えて deterministic な差分 sequence 全体に束縛されます。
いずれかの database が変更された場合は `--cursor` なしで最初からやり直してください。

## フラグ互換性と移行

Expand Down
25 changes: 25 additions & 0 deletions changelog.d/unreleased/4859.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
category: security
issues:
- 4859
affected:
- src/CodeIndex/Cli/DiffCommandRunner.cs
- src/CodeIndex/Cli/DiffCommandOptionsParser.cs
- src/CodeIndex/Cli/DiffCursorCodec.cs
- src/CodeIndex/Cli/DiffResultWriter.cs
- src/CodeIndex/Cli/JsonOutputContracts.cs
- src/CodeIndex/Cli/ConsoleUi.cs
- tests/CodeIndex.Tests/DiffCommandRunnerTests.cs
- tests/CodeIndex.Tests/DiffCommandHelpersTests.cs
- tests/CodeIndex.Tests/ExportImportCommandRunnerTests.cs
- TESTING_GUIDE.md
- USER_GUIDE.md
---

## English

- **Detailed database diffs are now structured, redacted, and byte-bounded by default (#4859)** — `diff --detailed --json` emits named fields with hashes and byte lengths instead of opaque source-bearing rows, caps the complete UTF-8 JSON output at 1 MiB by default, and returns count, truncation, cursor, and replay metadata. Cursors bind the deterministic difference sequence and reject changed database contents. Callers can set `--max-json-bytes`, resume with `--cursor`, or explicitly opt into source and path values with `--include-content`.

## 日本語

- **詳細 database diff を既定で構造化・秘匿化し、byte 上限を適用するようになりました (#4859)** — `diff --detailed --json` は source を含み得る opaque row の代わりに hash と byte length を持つ名前付き field を出力し、UTF-8 JSON 全体を既定で 1 MiB に制限して、件数・truncation・cursor・replay metadata を返します。cursor は deterministic な差分 sequence に束縛され、database 内容が変わると拒否されます。caller は `--max-json-bytes` で上限を指定し、`--cursor` で再開できます。source と path の値が必要な場合だけ `--include-content` で明示的に opt-in できます。
2 changes: 1 addition & 1 deletion src/CodeIndex/Cli/ConsoleUi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ private static readonly (string Command, string Usage)[] CommandUsageLines =
("db-checkpoints", "cdidx db checkpoints --list|--delete <name<=128>|--prune [--keep <n>] [--dry-run] [--db <path>] [--json]"),
("db-restore", "cdidx db restore <name<=128> [--dry-run] [--db <path>] [--json]"),
("db-restore-backups", "cdidx db restore-backups --list|--prune [--keep <n>] [--dry-run] [--db <path>] [--json]"),
("diff", "cdidx diff <db1> <db2> [--json] [--summary-only] [--detailed] [--limit <n<=10000>] [--offset <n>]"),
("diff", $"cdidx diff <db1> <db2> [--json] [--summary-only] [--detailed] [--include-content] [--max-json-bytes <n={DiffCommandRunner.MinDiffJsonBytes}..{DiffCommandRunner.MaxDiffJsonBytes}>] [--limit <n<=10000>] [--offset <n>|--cursor <cursor>]"),
("report", "cdidx report --output <bundle.tgz> [--overwrite] [--db <path>] [--json] [--redact-paths] [--log-lines <n<=2000>] [--no-log] [--include-args]"),
("validate", "cdidx validate [--db <path>] [--json[=array]] [--format <text|json|count|compact|csv|tsv|lsp|qf|sarif>] [--verbose] [--limit <n>|--top <n>] [--kind <kind>] [--severity <info|warning|error>] [--path <glob>]"),
("impact", "cdidx impact <query>|--query <query>|-- <query> [--db <path>] [--json] [--format <text|json|compact>] [--compact] [--fields <csv>] [--cursor <next_cursor>] [--max-json-bytes <n>] [--verbose] [--limit <n>|--top <n>] [--lang <lang>] [--path <glob>] [--exclude-path <glob>] [--exclude-tests] [--body] [--snippet-lines <n>] [--max-line-width <n>] [--max-hops <n>] [--exact-name] [--count] [--with-paths]"),
Expand Down
Loading
Loading