-
Notifications
You must be signed in to change notification settings - Fork 4
Update analyzers and add flake8 checks Phase II #109
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
9b328cb
4e3ca22
ab375e2
4ddfd41
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 |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| [flake8] | ||
| max-line-length = 100 | ||
| extend-ignore = E203, W503 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,13 +4,14 @@ name: Auto-label Bot | |
| on: | ||
| issues: | ||
| types: [opened, edited] | ||
| pull_request: | ||
| pull_request_target: | ||
| types: [opened, edited, synchronize] | ||
|
|
||
| # Default permissions for the workflow | ||
| permissions: | ||
| contents: read | ||
| issues: write | ||
| pull-requests: write | ||
|
Comment on lines
+10
to
14
Contributor
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. 🧩 Analysis chain🌐 Web query:
💡 Result: Minimum required
is: permissions:
pull-requests: writeBecause listing PR files requires If you prefer splitting permissions, this also works: permissions:
pull-requests: read
issues: write[1] (docs.github.com) Citations:
🏁 Script executed: cat -n .github/workflows/auto-label.ymlRepository: Refactron-ai/Refactron_lib Length of output: 10030 Fix the proposed permissions — The concern about The correct approach is to keep
🔐 Corrected fix permissions:
contents: read
issues: write
- pull-requests: write
+ pull-requests: read
jobs:
label-issues:
if: github.event_name == 'issues'
+ permissions:
+ issues: write
runs-on: ubuntu-latest
label-pull-requests:
if: github.event_name == 'pull_request_target'
+ permissions:
+ contents: read
+ pull-requests: read
+ issues: write
runs-on: ubuntu-latest🤖 Prompt for AI Agents |
||
| contents: read | ||
|
|
||
| jobs: | ||
| label-issues: | ||
|
|
@@ -20,6 +21,7 @@ jobs: | |
| - name: Auto-label issues | ||
| uses: actions/github-script@v8 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const { owner, repo, number } = context.issue; | ||
| const issue = context.payload.issue; | ||
|
|
@@ -116,7 +118,7 @@ jobs: | |
| } | ||
|
|
||
| label-pull-requests: | ||
| if: github.event_name == 'pull_request' | ||
| if: github.event_name == 'pull_request_target' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout code | ||
|
|
@@ -127,6 +129,7 @@ jobs: | |
| - name: Auto-label PRs | ||
| uses: actions/github-script@v8 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const { owner, repo, number } = context.issue; | ||
| const pr = context.payload.pull_request; | ||
|
|
||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,15 +3,25 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ast | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import copy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Dict, List, Set | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Dict, List, Optional, Set | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from refactron.analyzers.base_analyzer import BaseAnalyzer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from refactron.core.config import RefactronConfig | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from refactron.core.models import CodeIssue, IssueCategory, IssueLevel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from refactron.llm.orchestrator import LLMOrchestrator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class CodeSmellAnalyzer(BaseAnalyzer): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Detects common code smells and anti-patterns.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def __init__( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config: RefactronConfig, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| orchestrator: Optional[LLMOrchestrator] = None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super().__init__(config) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.orchestrator = orchestrator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @property | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def name(self) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "code_smells" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -51,6 +61,29 @@ def analyze(self, file_path: Path, source_code: str) -> List[CodeIssue]: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issues.append(issue) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # AI Triage: Filter out safe/intentional smells | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if self.config.enable_ai_triage and self.orchestrator and issues: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Batch evaluate all issues | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+66
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # evaluate_issues_batch returns Dict[str, float] mapping issue_id to confidence | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| confidence_scores = self.orchestrator.evaluate_issues_batch(issues, source_code) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+69
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Filter issues with a confidence < 0.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (meaning LLM thinks it might be a false positive/safe) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final_issues = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for i, issue in enumerate(issues): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # evaluate_issues_batch defaults to f"issue_{i}" if rule_id is absent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issue_id = getattr(issue, "rule_id", None) or f"issue_{i}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+66
to
+75
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Batch evaluate all issues | |
| # evaluate_issues_batch returns Dict[str, float] mapping issue_id to confidence | |
| confidence_scores = self.orchestrator.evaluate_issues_batch(issues, source_code) | |
| # Filter issues with a confidence < 0.3 | |
| # (meaning LLM thinks it might be a false positive/safe) | |
| final_issues = [] | |
| for i, issue in enumerate(issues): | |
| # evaluate_issues_batch defaults to f"issue_{i}" if rule_id is absent | |
| issue_id = getattr(issue, "rule_id", None) or f"issue_{i}" | |
| # Assign a unique, stable triage ID per issue to avoid key collisions | |
| for i, issue in enumerate(issues): | |
| # Use rule_id, file path, and line number to help uniqueness and traceability | |
| rule_id = getattr(issue, "rule_id", "GENERIC") | |
| line_number = getattr(issue, "line_number", 0) or 0 | |
| triage_id = f"{rule_id}:{file_path}:{line_number}:{i}" | |
| # Ensure metadata exists and record the triage ID | |
| if getattr(issue, "metadata", None) is None: | |
| issue.metadata = {} | |
| issue.metadata.setdefault("triage_id", triage_id) | |
| # Batch evaluate all issues | |
| # evaluate_issues_batch returns Dict[str, float] mapping triage_id to confidence | |
| confidence_scores = self.orchestrator.evaluate_issues_batch(issues, source_code) | |
| # Filter issues with a confidence < 0.3 | |
| # (meaning LLM thinks it might be a false positive/safe) | |
| final_issues = [] | |
| for i, issue in enumerate(issues): | |
| # Use the unique triage_id; fall back to a per-index ID if missing | |
| issue_id = issue.metadata.get("triage_id") if getattr(issue, "metadata", None) else None | |
| if not issue_id: | |
| issue_id = f"issue_{i}" |
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.
Don’t use rule_id as the confidence key.
rule_id identifies the rule (S004, S005, etc.), not the individual finding. Two missing-docstring issues in the same file would share one key and be kept or dropped together with the same score. Use a stable per-issue identifier, or have the batch API return scores aligned to input order.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@refactron/analyzers/code_smell_analyzer.py` around lines 73 - 77, The code is
using issue.rule_id as the key into confidence_scores which groups different
findings of the same rule together; instead, construct and use a stable
per-issue identifier (or rely on an index-aligned API) when looking up
confidence. Change the lookup in the loop inside the analyzer (where issues are
enumerated) to compute a stable id such as getattr(issue, "id", None) or a
deterministic composite like
f"{getattr(issue,'path','')}-{getattr(issue,'line',0)}-{getattr(issue,'col',0)}-{getattr(issue,'rule_id','')}"
and use that key for confidence_scores.get(..., 1.0); alternatively update
evaluate_issues_batch to return scores in input order so you can use the
enumerate index i to index into the returned scores.
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.
Fail open when AI triage is unavailable.
evaluate_issues_batch() is an external/injected call, and right now any exception here will make analyze() raise after all findings were already collected. Please catch triage failures and fall back to the original issues.
Suggested fallback
# AI Triage: Filter out safe/intentional smells
if self.config.enable_ai_triage and self.orchestrator and issues:
- # Batch evaluate all issues
- # evaluate_issues_batch returns Dict[str, float] mapping issue_id to confidence
- confidence_scores = self.orchestrator.evaluate_issues_batch(issues, source_code)
+ try:
+ # Batch evaluate all issues
+ # evaluate_issues_batch returns Dict[str, float] mapping issue_id to confidence
+ confidence_scores = self.orchestrator.evaluate_issues_batch(
+ issues, source_code
+ )
+ except Exception:
+ return issues📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # AI Triage: Filter out safe/intentional smells | |
| if self.config.enable_ai_triage and self.orchestrator and issues: | |
| # Batch evaluate all issues | |
| # evaluate_issues_batch returns Dict[str, float] mapping issue_id to confidence | |
| confidence_scores = self.orchestrator.evaluate_issues_batch(issues, source_code) | |
| # Filter issues with a confidence < 0.3 | |
| # (meaning LLM thinks it might be a false positive/safe) | |
| final_issues = [] | |
| for i, issue in enumerate(issues): | |
| # evaluate_issues_batch defaults to f"issue_{i}" if rule_id is absent | |
| issue_id = getattr(issue, "rule_id", None) or f"issue_{i}" | |
| confidence = confidence_scores.get(issue_id, 1.0) | |
| # Optional: Attach the confidence score to the issue metadata | |
| # for reporting/debugging | |
| issue.metadata["validation_confidence"] = confidence | |
| if confidence >= 0.3: | |
| final_issues.append(issue) | |
| issues = final_issues | |
| # AI Triage: Filter out safe/intentional smells | |
| if self.config.enable_ai_triage and self.orchestrator and issues: | |
| try: | |
| # Batch evaluate all issues | |
| # evaluate_issues_batch returns Dict[str, float] mapping issue_id to confidence | |
| confidence_scores = self.orchestrator.evaluate_issues_batch( | |
| issues, source_code | |
| ) | |
| except Exception: | |
| return issues | |
| # Filter issues with a confidence < 0.3 | |
| # (meaning LLM thinks it might be a false positive/safe) | |
| final_issues = [] | |
| for i, issue in enumerate(issues): | |
| # evaluate_issues_batch defaults to f"issue_{i}" if rule_id is absent | |
| issue_id = getattr(issue, "rule_id", None) or f"issue_{i}" | |
| confidence = confidence_scores.get(issue_id, 1.0) | |
| # Optional: Attach the confidence score to the issue metadata | |
| # for reporting/debugging | |
| issue.metadata["validation_confidence"] = confidence | |
| if confidence >= 0.3: | |
| final_issues.append(issue) | |
| issues = final_issues |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@refactron/analyzers/code_smell_analyzer.py` around lines 64 - 85, The AI
triage call evaluate_issues_batch in analyze() can raise exceptions and
currently will bubble up and fail the whole analysis; wrap the call and
subsequent processing in a try/except that catches any Exception (or specific
orchestration errors) and logs the failure, then fall back to leaving issues
unchanged (i.e., do not filter) when self.config.enable_ai_triage and
self.orchestrator are present; ensure you still attach no confidence metadata on
failure and preserve the original issues list, and reference
evaluate_issues_batch, analyze, self.config.enable_ai_triage, and
self.orchestrator when locating the change.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,7 @@ | |
|
|
||
| import click | ||
| import requests # type: ignore | ||
| import yaml | ||
| import yaml # type: ignore | ||
|
Contributor
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. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n \
--glob 'pyproject.toml' \
--glob 'setup.cfg' \
--glob 'setup.py' \
--glob 'requirements*.txt' \
--glob 'Pipfile' \
--glob 'poetry.lock' \
--glob 'uv.lock' \
'types-PyYAML|PyYAML|ignore_missing_imports|import-untyped'Repository: Refactron-ai/Refactron_lib Length of output: 107 🏁 Script executed: # Check what yaml APIs are actually used in the file
rg -n 'yaml\.' refactron/cli.py | head -20Repository: Refactron-ai/Refactron_lib Length of output: 157 🏁 Script executed: # Check for mypy configuration
fd -e 'mypy.ini' -e '.mypy.ini' -e 'pyrightconfig.json' -e 'pyproject.toml' | xargs -I {} sh -c 'grep -l "mypy\|pyrightconfig\|type_check" {} 2>/dev/null || true'Repository: Refactron-ai/Refactron_lib Length of output: 52 🏁 Script executed: # Check if there are any other yaml-related ignores or comments in the file
rg -n 'yaml|type.*ignore' refactron/cli.pyRepository: Refactron-ai/Refactron_lib Length of output: 674 🏁 Script executed: cat pyproject.toml | head -100Repository: Refactron-ai/Refactron_lib Length of output: 2703 🏁 Script executed: cat pyproject.toml | tail -50Repository: Refactron-ai/Refactron_lib Length of output: 1108 Narrow or remove the blanket
🤖 Prompt for AI Agents |
||
| from rich import box | ||
| from rich.align import Align | ||
| from rich.console import Console | ||
|
|
@@ -1146,6 +1146,7 @@ def _interactive_file_selector(workspace_path: Path) -> Path: | |
| console.print( | ||
| f"\n[success]✓ Selected: {selected_path.relative_to(workspace_path)}[/success]\n" | ||
| ) | ||
| return Path(selected_path) | ||
| return cast(Path, selected_path) | ||
|
|
||
| except (KeyboardInterrupt, EOFError): | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,7 +4,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any, Dict, List, Optional | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| import yaml | ||||||||||||||||||||||||||||||||||||||||||||||
| import yaml # type: ignore | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| from refactron.core.config_loader import ConfigLoader | ||||||||||||||||||||||||||||||||||||||||||||||
| from refactron.core.config_validator import ConfigValidator | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -130,6 +130,9 @@ class RefactronConfig: | |||||||||||||||||||||||||||||||||||||||||||||
| pattern_learning_enabled: bool = True # Enable learning from feedback | ||||||||||||||||||||||||||||||||||||||||||||||
| pattern_ranking_enabled: bool = True # Enable ranking based on learned patterns | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| # AI Triage settings | ||||||||||||||||||||||||||||||||||||||||||||||
| enable_ai_triage: bool = False # Use LLM to filter false positive code smells | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+133
to
+135
Contributor
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.
Suggested follow-up# refactron/core/config_validator.py
boolean_fields = {
"show_details",
"require_preview",
"backup_enabled",
"enable_ast_cache",
"enable_incremental_analysis",
"enable_parallel_processing",
"use_multiprocessing",
"enable_memory_profiling",
"enable_console_logging",
"enable_file_logging",
"enable_metrics",
"metrics_detailed",
"enable_prometheus",
"enable_telemetry",
+ "enable_ai_triage",
"enable_pattern_learning",
"pattern_learning_enabled",
"pattern_ranking_enabled",
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| @classmethod | ||||||||||||||||||||||||||||||||||||||||||||||
| def from_file( | ||||||||||||||||||||||||||||||||||||||||||||||
| cls, | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -243,6 +246,7 @@ def to_file(self, config_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||
| "pattern_learning_enabled": self.pattern_learning_enabled, | ||||||||||||||||||||||||||||||||||||||||||||||
| "pattern_ranking_enabled": self.pattern_ranking_enabled, | ||||||||||||||||||||||||||||||||||||||||||||||
| "enable_ai_triage": self.enable_ai_triage, | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -254,6 +254,22 @@ def generate_documentation( | |
| ) | ||
|
|
||
| def evaluate_issues_batch(self, issues: List[CodeIssue], source_code: str) -> Dict[str, float]: | ||
| """Batch evaluate confidence for multiple issues. | ||
|
|
||
| Args: | ||
| issues: List of issues to evaluate. | ||
| source_code: The source code context. | ||
|
|
||
| Returns: | ||
| A dictionary mapping issue rule_ids (or fallback IDs) to a confidence score. | ||
| """ | ||
| # Default implementation returns 1.0 (high confidence) for all issues | ||
| # Can be enhanced to actually call the LLM for batch triage | ||
| scores = {} | ||
| for i, issue in enumerate(issues): | ||
| issue_id = getattr(issue, "rule_id", None) or f"issue_{i}" | ||
| scores[issue_id] = 1.0 | ||
| return scores | ||
|
Comment on lines
+266
to
+272
Contributor
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. Resolve the conflicting implementations in The unconditional Also applies to: 273-360 🤖 Prompt for AI Agents |
||
| """Evaluate a batch of issues for a single file to suppress false positives. | ||
|
|
||
| Args: | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,12 +5,13 @@ | |||||||||||||||||||||||||||||||||||||
| import json | ||||||||||||||||||||||||||||||||||||||
| from dataclasses import dataclass | ||||||||||||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||||||||||||
| from typing import Dict, List, Optional, cast | ||||||||||||||||||||||||||||||||||||||
| from typing import Any, Dict, List, Optional, cast | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+8
to
9
Contributor
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. Remove the duplicated Lines 8-9 import the same symbols twice, which matches the isort failure reported in CI. Keep a single 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||
| import chromadb | ||||||||||||||||||||||||||||||||||||||
| from chromadb.config import Settings | ||||||||||||||||||||||||||||||||||||||
| from sentence_transformers import SentenceTransformer | ||||||||||||||||||||||||||||||||||||||
| from sentence_transformers import SentenceTransformer # type: ignore | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| CHROMA_AVAILABLE = True | ||||||||||||||||||||||||||||||||||||||
| except ImportError: | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -60,6 +61,8 @@ def __init__( | |||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||
| if not CHROMA_AVAILABLE: | ||||||||||||||||||||||||||||||||||||||
| raise RuntimeError( | ||||||||||||||||||||||||||||||||||||||
| "ChromaDB is not available. Install with: " | ||||||||||||||||||||||||||||||||||||||
| "pip install chromadb sentence-transformers" | ||||||||||||||||||||||||||||||||||||||
| "ChromaDB is not available. " | ||||||||||||||||||||||||||||||||||||||
| "Install with: pip install chromadb sentence-transformers" | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -182,6 +185,8 @@ def _index_file(self, file_path: Path, summarize: bool = False) -> List[CodeChun | |||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||
| summary = self._summarize_chunk(chunk) | ||||||||||||||||||||||||||||||||||||||
| if summary: | ||||||||||||||||||||||||||||||||||||||
| # Prepend summary to content for embedding | ||||||||||||||||||||||||||||||||||||||
| # (makes it searchable by plain English) | ||||||||||||||||||||||||||||||||||||||
| # Prepend summary for semantic searchability | ||||||||||||||||||||||||||||||||||||||
| chunk.content = f"Summary: {summary}\n\n{chunk.content}" | ||||||||||||||||||||||||||||||||||||||
| chunk.metadata["ai_summary"] = summary | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+188
to
192
Contributor
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. Keep
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
@@ -281,11 +286,13 @@ def _save_metadata(self, metadata: Dict[str, Any]) -> None: | |||||||||||||||||||||||||||||||||||||
| with open(metadata_file, "w") as f: | ||||||||||||||||||||||||||||||||||||||
| json.dump(metadata, f, indent=2) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def _load_metadata(self) -> Dict: | ||||||||||||||||||||||||||||||||||||||
| def _load_metadata(self) -> Dict[str, Any]: | ||||||||||||||||||||||||||||||||||||||
| """Load index metadata.""" | ||||||||||||||||||||||||||||||||||||||
| metadata_file = self.index_path / "metadata.json" | ||||||||||||||||||||||||||||||||||||||
| if not metadata_file.exists(): | ||||||||||||||||||||||||||||||||||||||
| return {} | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| with open(metadata_file, "r") as f: | ||||||||||||||||||||||||||||||||||||||
| return cast(Dict, json.load(f)) | ||||||||||||||||||||||||||||||||||||||
| return cast(Dict[str, Any], json.load(f)) | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+289
to
298
Contributor
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. 🧩 Analysis chain🏁 Script executed: head -n 310 refactron/rag/indexer.py | tail -n 30Repository: Refactron-ai/Refactron_lib Length of output: 1109 Restore a single The duplicate function header on lines 289-290 leaves the first definition without a body, causing an Suggested fix- def _load_metadata(self) -> Dict:
- def _load_metadata(self) -> Dict[str, Any]:
+ def _load_metadata(self) -> Dict[str, Any]:
"""Load index metadata."""
metadata_file = self.index_path / "metadata.json"
if not metadata_file.exists():
return {}
with open(metadata_file, "r") as f:
- return cast(Dict, json.load(f))
return cast(Dict[str, Any], json.load(f))📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Actions: Pre-commit[error] 290-290: Black: Cannot format due to parse error. IndentationError: expected an indented block at line 290. [error] 289-289: Flake8: IndentationError: expected an indented block after function definition on line 288. [error] 289-289: Mypy: Syntax error due to indentation issue at line 289. [error] 289-289: Flake8: IndentationError: expected an indented block after function definition on line 288. 🪛 Ruff (0.15.5)[warning] 290-290: Expected an indented block after function definition (invalid-syntax) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,23 +55,50 @@ def __init__(self) -> None: | |
| """Initialize the parser.""" | ||
| if not TREE_SITTER_AVAILABLE: | ||
| raise RuntimeError( | ||
| "tree-sitter is not available. Install with: " | ||
| "pip install tree-sitter tree-sitter-python" | ||
| "tree-sitter is not available. " | ||
| "Install with: pip install tree-sitter tree-sitter-python" | ||
| ) | ||
|
|
||
| # Initialize Python language - handle different tree-sitter API versions | ||
| lang = tspython.language() | ||
| lang_data = tspython.language() | ||
|
|
||
| # In some versions, tspython.language() already returns a Language object | ||
| if isinstance(lang, Language): | ||
| PY_LANGUAGE = lang | ||
| # Try to get a proper Language object | ||
| py_language = None | ||
| if isinstance(lang_data, Language): | ||
| py_language = lang_data | ||
| else: | ||
| # Try newer API first (single argument) | ||
| try: | ||
| PY_LANGUAGE = Language(lang) | ||
| except TypeError: | ||
| py_language = Language(lang_data) | ||
| except (TypeError, ValueError): | ||
| # Try older API (needs name) | ||
| try: | ||
| py_language = Language(lang_data, "python") | ||
| except (TypeError, ValueError): | ||
| try: | ||
| py_language = Language(lang_data, name="python") | ||
| except (TypeError, ValueError): | ||
| # Fallback to using the raw data if it can be used directly | ||
| py_language = lang_data | ||
|
|
||
| # Initialize Parser - handle different tree-sitter API versions | ||
| try: | ||
| self.parser = Parser(py_language) | ||
| except Exception: | ||
| # Older API might not take it in constructor | ||
| self.parser = Parser() | ||
| try: | ||
| self.parser.set_language(py_language) | ||
| except Exception: | ||
| # If everything fails, it might be due to a mismatch between | ||
| # tree-sitter-python and tree-sitter versions. | ||
| # There's not much more we can do here but raise with context. | ||
| raise RuntimeError( | ||
| "Failed to initialize tree-sitter parser with language " | ||
| f"data of type {type(lang_data)}" | ||
| ) | ||
|
Comment on lines
+87
to
+101
Contributor
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. 🧩 Analysis chain🏁 Script executed: cat -n refactron/rag/parser.py | sed -n '85,140p'Repository: Refactron-ai/Refactron_lib Length of output: 2859 Remove the stale The old initialization code is orphaned after the 🤖 Prompt for AI Agents |
||
| PY_LANGUAGE = Language(lang, "python") | ||
| except TypeError: | ||
| # Try using the path to the compiled library (for very old or CI bindings) | ||
|
|
||
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.
🧩 Analysis chain
🌐 Web query:
For GitHub Actions, what are the security implications of usingpull_request_targettogether withactions/checkout, and what is the recommended safe pattern for labeling/comment-only workflows?💡 Result:
Security implications (
pull_request_target+actions/checkout)pull_request_targetruns in the context of the base repo, and GitHub explicitly warns that running untrusted PR code under this trigger can lead to issues like cache poisoning and unintended access to write privileges or secrets. This event is intended for actions like labeling/commenting on PRs from forks, and you should avoid it if you need to build or run PR code. [1]pull_request_targetworkflow checks out the PR’s head commit (attacker-controlled) and then runs build/scripts. Even if you think you’re not using secrets, the job still has a privileged token available; and ifactions/checkoutleaves credentials available to later steps, that makes exfiltration easier. [2]actions/checkoutcan persist auth material for later git operations (and has evolved how it stores it), so treating any subsequent step as potentially able to access credentials is part of the risk model—especially dangerous if you’ve checked out attacker-controlled code. [2][3]Recommended safe pattern for labeling/comment-only workflows
Use
pull_request_targetwithout checking out PR code and with least-privilege token permissions, then interact with the PR only via the API (e.g.,actions/github-script).If you must use
actions/checkoutin apull_request_targetworkflow, only check out a trusted ref (typically the default branch / base repo ref) and do not execute PR-provided code; GitHub also recently reinforced thatpull_request_targetuses the default branch as the workflow source/reference, but still notes the elevated-risk nature of the event. [4]Sources: GitHub docs warning on
pull_request_target[1], GitHub Security Lab “Preventing pwn requests” (checkout + token/credential persistence risk) [2],actions/checkoutdocs (credential persistence behavior) [3], GitHub Changelog onpull_request_targetdefault-branch execution + risk note [4].🏁 Script executed:
Repository: Refactron-ai/Refactron_lib
Length of output: 6512
🏁 Script executed:
Repository: Refactron-ai/Refactron_lib
Length of output: 2462
Remove the checkout step from the
pull_request_targetjob—it is unnecessary and creates a security risk.This job only uses the GitHub API (
github.rest.pulls.listFiles,github.rest.issues.addLabels) and does not read or execute code from the repository. Runningactions/checkout@v6(lines 124–127) underpull_request_targetcreates an unnecessary privilege escalation: the workflow token becomes available in an environment where untrusted PR code is checked out, increasing the risk of credential exfiltration or unintended access to secrets..github/workflows/first-time-contributor.yml(lines 44–68) already demonstrates the safe pattern forpull_request_targetworkflows: interact with PRs only via the GitHub API without checking out code.Additionally, reduce workflow permissions to least-privilege: remove
contents: read(line 12) since the job does not access repository files.🔒 Proposed fix
jobs: label-pull-requests: if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - name: Auto-label PRs uses: actions/github-script@v8 with: github-token: ${{ secrets.GITHUB_TOKEN }}🤖 Prompt for AI Agents