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 changelog.d/unreleased/2904.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2904
affected:
- src/CodeIndex/Cli/IndexCommandRunner.Parse.cs
- tests/CodeIndex.Tests/IndexCommandRunnerTests.cs
---

## English

- **index parallelism now clamps oversized worker counts (#2904)** — `--parallelism` and `CDIDX_INDEX_PARALLELISM` values above the documented maximum warn and use the bounded worker count.

## 日本語

- **index parallelism が過大な worker 数を clamp するようになりました (#2904)** — `--parallelism` と `CDIDX_INDEX_PARALLELISM` が上限を超えた場合は warning を出し、制限された worker 数を使用します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2905.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2905
affected:
- src/CodeIndex/Mcp/McpToolFilter.cs
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP tool allow/deny filters now cap environment CSV input (#2905)** — overlong or overlarge MCP tool filter values are rejected before splitting; invalid `CDIDX_MCP_TOOLS_ALLOW` fails closed with no tools enabled, while invalid `CDIDX_MCP_TOOLS_DENY` leaves the default enabled set unchanged.

## 日本語

- **MCP tool allow/deny filter が環境変数 CSV 入力を制限するようになりました (#2905)** — 長すぎる、または entry 数が多すぎる MCP tool filter 値は split 前に拒否されます。無効な `CDIDX_MCP_TOOLS_ALLOW` は全 tool 無効の fail-closed となり、無効な `CDIDX_MCP_TOOLS_DENY` は既定の有効集合を維持します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2906.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2906
affected:
- src/CodeIndex/Cli/IndexCommandRunner.Parse.cs
- tests/CodeIndex.Tests/IndexCommandRunnerTests.cs
---

## English

- **index symbol-kind filters now cap CSV input before splitting (#2906)** — CLI and environment include/exclude symbol-kind lists reject oversized values before materializing entries.

## 日本語

- **index の symbol-kind filter が split 前に CSV 入力を制限するようになりました (#2906)** — CLI と環境変数の include/exclude symbol-kind list は、entry を materialize する前に過大な値を拒否します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2911.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2911
affected:
- src/CodeIndex/Cli/QueryCommandRunner.cs
- tests/CodeIndex.Tests/QueryCommandRunnerTests.cs
---

## English

- **CLI path filters now cap pattern count and length before SQL construction (#2911)** — `--path` and `--exclude-path` reject excessive repeated patterns or overlong values during argument validation.

## 日本語

- **CLI path filter が SQL 構築前に pattern 数と長さを制限するようになりました (#2911)** — `--path` と `--exclude-path` は、過剰な繰り返し pattern や長すぎる値を引数検証時に拒否します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2912.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2912
affected:
- src/CodeIndex/Cli/QueryCommandRunner.cs
- tests/CodeIndex.Tests/QueryCommandRunnerTests.cs
---

## English

- **CLI visibility filters now cap CSV input before splitting (#2912)** — `--visibility` and `--exclude-visibility` reject overlong or overlarge lists before deduplication.

## 日本語

- **CLI visibility filter が split 前に CSV 入力を制限するようになりました (#2912)** — `--visibility` と `--exclude-visibility` は、長すぎる、または entry 数が多すぎる list を dedup 前に拒否します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2913.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2913
affected:
- src/CodeIndex/Cli/QueryCommandRunner.cs
- tests/CodeIndex.Tests/QueryCommandRunnerTests.cs
---

## English

- **`status --check=<scopes>` now caps CSV input before splitting (#2913)** — overlong or overlarge scope lists fail with a usage error before allocating individual scope entries.

## 日本語

- **`status --check=<scopes>` が split 前に CSV 入力を制限するようになりました (#2913)** — 長すぎる、または entry 数が多すぎる scope list は個別 entry を割り当てる前に usage error として失敗します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2914.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2914
affected:
- src/CodeIndex/Cli/QueryCommandRunner.cs
- tests/CodeIndex.Tests/QueryCommandRunnerTests.cs
---

## English

- **repo map `--sections` now caps CSV input before splitting (#2914)** — oversized section lists are rejected with a usage error before allocating entries beyond the documented bound.

## 日本語

- **repo map の `--sections` が split 前に CSV 入力を制限するようになりました (#2914)** — 過大な section list は、上限を超える entry を割り当てる前に usage error として拒否されます。
53 changes: 51 additions & 2 deletions src/CodeIndex/Cli/IndexCommandRunner.Parse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public static partial class IndexCommandRunner
];

internal const string IndexParallelismEnvironmentVariable = "CDIDX_INDEX_PARALLELISM";
internal const int MaxIndexParallelism = 16;
internal const int MaxSymbolKindFilterCsvLength = 2048;
internal const int MaxSymbolKindFilterCsvEntries = 128;

public static IndexCommandOptions ParseArgs(string[] args)
{
Expand Down Expand Up @@ -356,6 +359,8 @@ private static void AddSymbolKindFilterValues(string source, string? value, List
{
if (value == null)
return;
if (!ValidateCsvBounds(source, value, MaxSymbolKindFilterCsvLength, MaxSymbolKindFilterCsvEntries, ref parseError))
return;

foreach (var raw in value.Split(',', StringSplitOptions.TrimEntries))
{
Expand All @@ -369,8 +374,46 @@ private static void AddSymbolKindFilterValues(string source, string? value, List
}
}

private static bool ValidateCsvBounds(
string source,
string value,
int maxLength,
int maxEntries,
ref string? parseError)
{
if (value.Length > maxLength)
{
parseError ??= $"{source} value is too long ({value.Length} characters; max {maxLength})";
return false;
}

var entries = CountCsvEntries(value);
if (entries > maxEntries)
{
parseError ??= $"{source} accepts at most {maxEntries} comma-separated entries";
return false;
}

return true;
}

private static int CountCsvEntries(string value)
{
if (value.Length == 0)
return 0;

var count = 1;
foreach (var ch in value)
{
if (ch == ',')
count++;
}

return count;
}

internal static int DefaultIndexParallelism()
=> Math.Clamp(Environment.ProcessorCount, 1, 16);
=> Math.Clamp(Environment.ProcessorCount, 1, MaxIndexParallelism);

private static int ReadIndexParallelismFromEnvironment()
{
Expand All @@ -385,7 +428,13 @@ private static int ReadIndexParallelismFromEnvironment()
private static int ParseIndexParallelism(string value, int fallback, string source)
{
if (int.TryParse(value, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out var parsed) && parsed > 0)
return parsed;
{
if (parsed <= MaxIndexParallelism)
return parsed;

Console.Error.WriteLine($"Warning: {source} value '{value}' exceeds the maximum {MaxIndexParallelism}; using {MaxIndexParallelism} / {source} 値 '{value}' は最大 {MaxIndexParallelism} を超えています。{MaxIndexParallelism} を使用します");
return MaxIndexParallelism;
}

Console.Error.WriteLine($"Warning: invalid {source} value '{value}' (ignored; use a positive integer) / 不正な {source} 値 '{value}'(無視。正の整数を指定)");
return fallback;
Expand Down
80 changes: 76 additions & 4 deletions src/CodeIndex/Cli/QueryCommandRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ public static class QueryCommandRunner
// OR 結合の `symbols` 名は SQLite の式木深さ上限 1000 を十分下回る値で頭打ちにし、
// 大量バッチを SQLite 例外ではなく明確な usage error で早期に弾く。
internal const int MaxSymbolQueryNames = 256;
internal const int MaxMapSectionsCsvLength = 256;
internal const int MaxMapSectionsCsvEntries = 16;
internal const int MaxStatusCheckScopesCsvLength = 256;
internal const int MaxStatusCheckScopesCsvEntries = 16;
internal const int MaxVisibilityFilterCsvLength = 256;
internal const int MaxVisibilityFilterCsvEntries = 16;
internal const int MaxQueryPathFilterCount = 128;
internal const int MaxQueryPathFilterLength = 1024;
internal const int ExactZeroHintProbeLimit = 1;
internal const int ExactZeroHintSampleLimit = 5;
private const string HotspotsGroupedByNameKind = "name_kind";
Expand Down Expand Up @@ -4979,6 +4987,8 @@ void AddStatusCheckScopes(string rawScopes)
AddParseError("Error: --check scope list cannot be empty. Use --check or --check=workspace,fold,graph,issues,hotspot,csharp,sql,newer.");
return;
}
if (!ValidateCsvBounds("--check", rawScopes, MaxStatusCheckScopesCsvLength, MaxStatusCheckScopesCsvEntries, AddParseError))
return;

statusCheckScopes ??= new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var rawScope in rawScopes.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
Expand Down Expand Up @@ -5684,6 +5694,9 @@ void WarnIfDuplicateSingleValueOption(string canonicalName, string newValue)
private static List<string> ParseMapSections(string rawValue, Action<string> addParseError)
{
var sections = new List<string>();
if (!ValidateCsvBounds("--sections", rawValue, MaxMapSectionsCsvLength, MaxMapSectionsCsvEntries, addParseError))
return sections;

foreach (var rawSection in rawValue.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
var section = rawSection.ToLowerInvariant();
Expand All @@ -5709,15 +5722,71 @@ private static List<string> ParseMapSections(string rawValue, Action<string> add
return sections.Distinct(StringComparer.Ordinal).ToList();
}

private static bool ValidateCsvBounds(
string optionName,
string rawValue,
int maxLength,
int maxEntries,
Action<string> addParseError)
{
if (rawValue.Length > maxLength)
{
addParseError($"Error: {optionName} value is too long ({rawValue.Length} characters; max {maxLength}).");
return false;
}

var entries = CountCsvEntries(rawValue);
if (entries > maxEntries)
{
addParseError($"Error: {optionName} accepts at most {maxEntries} comma-separated entries.");
return false;
}

return true;
}

private static int CountCsvEntries(string rawValue)
{
if (rawValue.Length == 0)
return 0;

var count = 1;
foreach (var ch in rawValue)
{
if (ch == ',')
count++;
}

return count;
}

private static void ValidateQueryPathOptionValues(
IReadOnlyList<string> pathPatterns,
IReadOnlyList<string> excludePaths,
Action<string> addParseError)
{
foreach (var pattern in pathPatterns)
ValidatePathGlobPattern("--path", pattern, addParseError);
foreach (var pattern in excludePaths)
ValidatePathGlobPattern("--exclude-path", pattern, addParseError);
ValidatePathOptionValues("--path", pathPatterns, addParseError);
ValidatePathOptionValues("--exclude-path", excludePaths, addParseError);
}

private static void ValidatePathOptionValues(
string optionName,
IReadOnlyList<string> patterns,
Action<string> addParseError)
{
if (patterns.Count > MaxQueryPathFilterCount)
addParseError($"Error: {optionName} accepts at most {MaxQueryPathFilterCount} values.");

foreach (var pattern in patterns)
{
if (pattern.Length > MaxQueryPathFilterLength)
{
addParseError($"Error: {optionName} value is too long ({pattern.Length} characters; max {MaxQueryPathFilterLength}).");
continue;
}

ValidatePathGlobPattern(optionName, pattern, addParseError);
}
}

private static bool TryParseJsonOutputFormat(string rawValue, out string format)
Expand Down Expand Up @@ -6442,6 +6511,9 @@ private static bool TryWriteParseError(QueryCommandOptions options, string comma

private static void AddVisibilityFilterValues(string optionName, string rawValue, List<string> target, Action<string> addParseError)
{
if (!ValidateCsvBounds(optionName, rawValue, MaxVisibilityFilterCsvLength, MaxVisibilityFilterCsvEntries, addParseError))
return;

var values = rawValue
.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
.Select(value => value.ToLowerInvariant())
Expand Down
Loading
Loading