-
Notifications
You must be signed in to change notification settings - Fork 731
fix: prevent processing 3rd party maintainers [CM-1097] #4035
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
94b4514
8b8bac8
3e53c4c
d2a588f
5529bd2
639b271
30a466d
308301a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,6 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import asyncio | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import re | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import time as time_module | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from datetime import datetime, time, timezone | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from decimal import Decimal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -130,6 +131,49 @@ class MaintainerService(BaseService): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "code-of-conduct.md", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Exact directory-name matches (the dir component must equal one of these) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| THIRD_PARTY_DIR_EXACT = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "vendor", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "node_modules", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "3rdparty", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "3rd_party", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "third_party", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "third-party", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "thirdparty", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "external", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "external_packages", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "externallibs", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "extern", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "ext", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deps", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deps_src", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "dependencies", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "depend", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "bundled", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "bundled_deps", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "pods", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "godeps", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "bower_components", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "bower_components_external", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "gems", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "internal-complibs", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "runtime-library", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "submodules", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "lib-src", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "lib-python", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "contrib", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "vendored", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Versioned directory pattern — directories containing semver-like numbers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (e.g. "jquery-ui-1.12.1", "zlib-1.2.8", "ffmpeg-7.1.1") are almost always | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # bundled third-party packages. Real project directories don't have versions. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _VERSION_DIR_RE = re.compile(r"\d+\.\d+") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Version regex matches non-version directory namesLow Severity
Additional Locations (1)Reviewed by Cursor Bugbot for commit 639b271. Configure here. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Hard max depth (number of path segments). Files deeper than this are rejected | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # regardless of content — legitimate governance files live at depth 1-3. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MAX_PATH_DEPTH = 3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+173
to
+175
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FULL_PATH_SCORE = 100 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| STEM_MATCH_SCORE = 50 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PARTIAL_STEM_SCORE = 25 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -145,6 +189,32 @@ async def _read_text_file(file_path: str) -> str: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async with aiofiles.open(file_path, "rb") as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return safe_decode(await f.read()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @classmethod | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _is_third_party_path(cls, path: str) -> bool: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Check if a file path looks like third-party/vendored code. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Three rules (any match → reject): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. A directory component exactly matches a known vendor/dep directory name. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. A directory component contains a semver-like version (e.g. "zlib-1.2.8"). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. Path has more than MAX_PATH_DEPTH segments (hard cap, no exceptions). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| low = path.lower().replace("\\", "/") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parts = low.split("/") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dirs = parts[:-1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for part in dirs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if part in cls.THIRD_PARTY_DIR_EXACT: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if part.endswith(".dist-info"): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if cls._VERSION_DIR_RE.search(part): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(parts) > cls.MAX_PATH_DEPTH: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Depth limit unconditionally rejects all deep governance filesMedium Severity The PR description explicitly states the depth limit ( Additional Locations (1)Reviewed by Cursor Bugbot for commit 639b271. Configure here.
Comment on lines
+201
to
+214
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def make_role(self, title: str): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title = title.lower() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -278,19 +348,47 @@ async def save_maintainers( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo_id, repo_url, maintainers, change_date=today_midnight | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def get_extraction_prompt(self, filename: str, content_to_analyze: str) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def get_extraction_prompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self, filename: str, content_to_analyze: str, repo_url: str = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Generates the full prompt for the LLM to extract maintainer information, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using both file content and filename as context. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using file content, filename, and repo URL as context. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return f""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Your task is to extract every person listed in the file content provided below, regardless of which section they appear in. Follow these rules precisely: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Third-Party Check (MANDATORY — evaluate FIRST)**: Examine the **full file path** and the **repository URL** below. You MUST return `{{"error": "not_found"}}` immediately if ANY of these rules match: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Rule 1 — Repo-name check (step by step)**: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. Extract the repo name and org name from the repository URL (e.g. URL `https://github.com/numworks/epsilon` → repo=`epsilon`, org=`numworks`). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. For each directory in the file path, check: is this directory name a common structural directory (like `src`, `docs`, `doc`, `.github`, `lib`, `pkg`, `test`, `community`, `content`, `tools`, `web`, `app`, `config`, `deploy`, `charts`, etc.)? If yes, skip it — it's fine. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. For any directory that is NOT a common structural directory AND is NOT a governance keyword (maintainer, owner, contributor, etc.), check: does it appear as a substring of the repo name or org name, or vice versa? If NOT → this directory is a submodule or bundled library name that does not belong to this repo. Return `{{"error": "not_found"}}`. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Example: file `mylib/README.md` in repo `orgname/myproject` → `mylib` is not structural, not a governance keyword, and `mylib` does not appear in `myproject` or `orgname` → reject. But file `myproject/README.md` in the same repo → `myproject` matches the repo name → allow. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+363
to
+367
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Rule 1 — Repo-name check (step by step)**: | |
| 1. Extract the repo name and org name from the repository URL (e.g. URL `https://github.com/numworks/epsilon` → repo=`epsilon`, org=`numworks`). | |
| 2. For each directory in the file path, check: is this directory name a common structural directory (like `src`, `docs`, `doc`, `.github`, `lib`, `pkg`, `test`, `community`, `content`, `tools`, `web`, `app`, `config`, `deploy`, `charts`, etc.)? If yes, skip it — it's fine. | |
| 3. For any directory that is NOT a common structural directory AND is NOT a governance keyword (maintainer, owner, contributor, etc.), check: does it appear as a substring of the repo name or org name, or vice versa? If NOT → this directory is a submodule or bundled library name that does not belong to this repo. Return `{{"error": "not_found"}}`. | |
| Example: file `mylib/README.md` in repo `orgname/myproject` → `mylib` is not structural, not a governance keyword, and `mylib` does not appear in `myproject` or `orgname` → reject. But file `myproject/README.md` in the same repo → `myproject` matches the repo name → allow. | |
| **Rule 1 — Repo/org-name context (advisory only)**: | |
| You may extract the repo name and org name from the repository URL (e.g. URL `https://github.com/numworks/epsilon` → repo=`epsilon`, org=`numworks`) as weak supporting context when reasoning about ambiguous paths. | |
| However, do **not** reject a file solely because a directory name does not match, contain, or resemble the repo name or org name. Repo/org-name similarity is not a deterministic third-party check by itself. |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prompt Rule 1 (repo-name/org-name substring heuristic) is enforced only by the LLM instruction; the backend _is_third_party_path logic doesn’t implement this rule. That makes third-party rejection behavior non-deterministic and hard to debug (a file can be rejected by the model without any corresponding backend log/guardrail). Consider either implementing the same repo-name heuristic server-side (so skips are explainable and consistent) or removing/softening this rule in the prompt to match backend behavior.
| - **Third-Party Check (MANDATORY — evaluate FIRST)**: Examine the **full file path** and the **repository URL** below. You MUST return `{{"error": "not_found"}}` immediately if ANY of these rules match: | |
| **Rule 1 — Repo-name check (step by step)**: | |
| 1. Extract the repo name and org name from the repository URL (e.g. URL `https://github.com/numworks/epsilon` → repo=`epsilon`, org=`numworks`). | |
| 2. For each directory in the file path, check: is this directory name a common structural directory (like `src`, `docs`, `doc`, `.github`, `lib`, `pkg`, `test`, `community`, `content`, `tools`, `web`, `app`, `config`, `deploy`, `charts`, etc.)? If yes, skip it — it's fine. | |
| 3. For any directory that is NOT a common structural directory AND is NOT a governance keyword (maintainer, owner, contributor, etc.), check: does it appear as a substring of the repo name or org name, or vice versa? If NOT → this directory is a submodule or bundled library name that does not belong to this repo. Return `{{"error": "not_found"}}`. | |
| Example: file `mylib/README.md` in repo `orgname/myproject` → `mylib` is not structural, not a governance keyword, and `mylib` does not appear in `myproject` or `orgname` → reject. But file `myproject/README.md` in the same repo → `myproject` matches the repo name → allow. | |
| **Rule 2 — Vendor/dependency directory**: reject if any directory in the path is one of: | |
| `vendor`, `node_modules`, `3rdparty`, `3rd_party`, `third_party`, `thirdparty`, `third-party`, `external`, `external_packages`, `extern`, `ext`, `deps`, `deps_src`, `dependencies`, `depend`, `bundled`, `bundled_deps`, `Pods`, `Godeps`, `bower_components`, `gems`, `submodules`, `internal-complibs`, `runtime-library`, `lib-src`, `lib-python`, `contrib`, `vendored`, or ends with `.dist-info`. | |
| **Rule 3 — Versioned directory**: reject if any directory in the path contains a version number pattern like `X.Y` or `X.Y.Z` (e.g. `jquery-ui-1.12.1`, `zlib-1.2.8`, `ffmpeg-7.1.1`, `mesa-24.0.2`). Versioned directories are almost always bundled third-party packages. | |
| **Rule 4 — Hard depth limit**: reject if the path has more than 3 segments (e.g. `a/b/c/file` is 4 segments → reject). Legitimate governance files live at the root or 1-2 directories deep. No exceptions. | |
| **Examples of paths that MUST be rejected:** | |
| - `src/somelibrary/AUTHORS` in a repo that is NOT somelibrary (Rule 1) | |
| - `subcomponent/README.md` in a repo with a different project name (Rule 1) | |
| - `vendor/some-package/MAINTAINERS.md` (Rule 2: vendor) | |
| - `node_modules/some-pkg/README.md` (Rule 2: node_modules) | |
| - `bundled/pkg-1.2.0/README.md` (Rule 2 + Rule 3: version) | |
| - `a/b/c/d/AUTHORS.txt` (Rule 4: more than 3 segments) | |
| - **Third-Party Check (MANDATORY — evaluate FIRST)**: Examine the **full file path** below. You MUST return `{{"error": "not_found"}}` immediately if ANY of these rules match: | |
| **Rule 1 — Vendor/dependency directory**: reject if any directory in the path is one of: | |
| `vendor`, `node_modules`, `3rdparty`, `3rd_party`, `third_party`, `thirdparty`, `third-party`, `external`, `external_packages`, `extern`, `ext`, `deps`, `deps_src`, `dependencies`, `depend`, `bundled`, `bundled_deps`, `Pods`, `Godeps`, `bower_components`, `gems`, `submodules`, `internal-complibs`, `runtime-library`, `lib-src`, `lib-python`, `contrib`, `vendored`, or ends with `.dist-info`. | |
| **Rule 2 — Versioned directory**: reject if any directory in the path contains a version number pattern like `X.Y` or `X.Y.Z` (e.g. `jquery-ui-1.12.1`, `zlib-1.2.8`, `ffmpeg-7.1.1`, `mesa-24.0.2`). Versioned directories are almost always bundled third-party packages. | |
| **Rule 3 — Hard depth limit**: reject if the path has more than 3 segments (e.g. `a/b/c/file` is 4 segments → reject). Legitimate governance files live at the root or 1-2 directories deep. No exceptions. | |
| **Examples of paths that MUST be rejected:** | |
| - `vendor/some-package/MAINTAINERS.md` (Rule 1: vendor) | |
| - `node_modules/some-pkg/README.md` (Rule 1: node_modules) | |
| - `bundled/pkg-1.2.0/README.md` (Rule 1 + Rule 2: version) | |
| - `a/b/c/d/AUTHORS.txt` (Rule 3: more than 3 segments) |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_is_third_party_path is only applied inside analyze_and_build_result, which means candidate discovery (find_candidate_files) can still end up reading and scoring large vendored files (and incurring I/O + decode cost) before being rejected here. If the goal is to reduce third-party impact and cost, consider applying the third-party/path-depth filter earlier (e.g., skip paths in _ripgrep_search/find_candidate_files before _read_text_file) to avoid unnecessary file reads and processing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Third-party filtering missing from candidate discovery stage
Medium Severity
_is_third_party_path is only checked inside analyze_and_build_result, but find_candidate_files does not pre-filter third-party paths. Since only the single top-scoring subdir candidate is ever tried (line 848), a high-scoring third-party file (e.g. vendor/lib/MAINTAINERS.md) can shadow legitimate lower-scoring subdir candidates (e.g. docs/MAINTAINERS.md). The rejected third-party file causes an immediate fallthrough to expensive AI file detection, skipping all other valid subdir candidates entirely.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 30a466d. Configure here.


Uh oh!
There was an error while loading. Please reload this page.