What I built

For Hacktoberfest 2026 Week 2's Side Hustle challenge, I built SecureLocal AI: an offline-first desktop tool for a first-pass review of Python source code.

The scanner uses Python's built-in AST to flag seven heuristic patterns: dynamic execution, unsafe pickle deserialization, shell-enabled subprocess calls, possible hardcoded credentials, weak hashes, disabled TLS verification in recognized HTTP clients, and dynamically constructed SQL. It scans selected .py files without importing or executing the project, and its findings remain deterministic whether or not a language model is installed.

I tested the application end to end during development. This is an early working tool—not a claim of customer adoption or proven commercial demand.

Who might pay for it?

The plausible buyer is someone who needs a low-friction first review but cannot or does not want to upload source code to a hosted scanner: an independent Python consultant handling client repositories, or a small development team that wants a local triage step before human review. A paid offering might eventually be useful as a supported desktop workflow or team setup, but that is a market hypothesis, not a validated business. I have no paying customers, customer feedback, or commercial validation to report.

Why open innovation matters here

The static scanner is useful on its own. When a developer wants more context, SecureLocal AI can ask a locally running Ollama service to explain one selected finding using the open-weight Qwen2.5-Coder 3B model (qwen2.5-coder:3b). The model is optional; the app does not download it automatically. Install Ollama, start its local service, and pull the model yourself:

ollama pull qwen2.5-coder:3b python app.py 

The client defaults to http://127.0.0.1:11434 and rejects non-loopback endpoints. A normal scan makes no HTTP/API requests. Only after the user explicitly asks for an explanation does the app send a small, redacted finding context to local Ollama—not the project, source file, file path, or report. The model adds advice; it does not set severity, change the deterministic finding, edit files, or apply a fix. Its explanation is unverified and should be checked independently.

Running inference locally avoids per-request cloud-model charges and means source files do not need to leave the machine for this workflow. It is not cost-free: the user supplies the compute, electricity, storage, and initial model download, and local performance depends on their hardware. I have not measured or benchmarked it. Keeping the model choice and inference on the developer's machine also gives users more control than making a hosted model API a required dependency.

How the app works

The Tkinter interface lets me choose a project folder, start a scan, filter results by severity or text, and inspect a finding's rule, severity, confidence, location, redacted evidence, limitations, and remediation guidance. Findings can be exported as JSON or Markdown. Reports include the findings and relative paths, with credential-like evidence redacted; they do not include complete source files.

File discovery and scanning have safety limits and skip symbolic links, generated directories, oversized files, malformed source, and files that cannot be safely read. The app does not write to the scanned project. These controls reduce accidental exposure and unbounded work, but they do not protect against a compromised operating system or malicious local software. Review any report before sharing it.

Demo: screenshots from the repository

SecureLocal AI is a desktop application, so these existing screenshots are the demo rather than a hosted web instance.

Vulnerable scan and finding list

SecureLocal AI showing detected findings

Clean fixture scan

SecureLocal AI showing a clean fixture scan

Finding inspection

Finding details with severity, evidence, limitations, and remediation

Optional local-model explanation

An explanation from the locally running model

The image files are committed under docs/screenshots/. The image links above use their raw GitHub URLs so DEV can render the existing assets.

Testing and limitations

A recorded development result was 51 tests passing, exercising the scanner, rules and redaction, file discovery, exports, Ollama client behavior, and UI paths. The suite includes synthetic fixtures and mocked model responses; passing tests is evidence that those tested behaviors worked, not proof of complete security coverage or real-world detection accuracy.

The rules are heuristics: they can miss vulnerabilities and flag safe code, and they do not establish whether a value is attacker-controlled. This is Python-only first-pass triage, not full data-flow analysis, dependency scanning, a clean bill of health, or a replacement for review by a security professional.

Project and challenge

GitHub Copilot Session
You

attachment:Pasted text #1

Agent
▸ view {"path":"c:\\Users\\Kushal\\AppData\\Roaming\\Code\\agentSessionData\\d44184e...
{ "path": "c:\\Users\\Kushal\\AppData\\Roaming\\Code\\agentSessionData\\d44184ed-dfb2-4d6f-af7c-6d9b6e7fa524\\attachments\\8ce6204b-ebe2-4657-8262-bb48d712d66f\\Pasted text #1.txt", "view_range": [ 1, 260 ] }
 diff --git a/c:/Users/Kushal/AppData/Roaming/Code/agentSessionData/d44184ed-dfb2-4d6f-af7c-6d9b6e7fa524/attachments/8ce6204b-ebe2-4657-8262-bb48d712d66f/Pasted text #1.txt b/c:/Users/Kushal/AppData/Roaming/Code/agentSessionData/d44184ed-dfb2-4d6f-af7c-6d9b6e7fa524/attachments/8ce6204b-ebe2-4657-8262-bb48d712d66f/Pasted text #1.txt index 0000000..0000000 100644 --- a/c:/Users/Kushal/AppData/Roaming/Code/agentSessionData/d44184ed-dfb2-4d6f-af7c-6d9b6e7fa524/attachments/8ce6204b-ebe2-4657-8262-bb48d712d66f/Pasted text #1.txt +++ b/c:/Users/Kushal/AppData/Roaming/Code/agentSessionData/d44184ed-dfb2-4d6f-af7c-6d9b6e7fa524/attachments/8ce6204b-ebe2-4657-8262-bb48d712d66f/Pasted text #1.txt @@ -1,260 +1,260 @@ # Task: Professionally redesign the existing SecureLocal AI Tkinter frontend You are working on my existing Python project, **SecureLocal AI — Offline-First Code Security Auditor & Remediation Assistant**. I want you to upgrade the visual design of the existing Tkinter desktop application so that it looks like a polished, professional developer security product suitable for a project challenge submission and portfolio demonstration. ## 1. First, inspect the existing project Before editing anything: 1. Inspect the project structure, especially `app.py`, everything under `ui/`, and the existing tests. 2. Identify which files implement: - The main application window and layout. - Project-folder selection and scanning controls. - The findings table, severity filters, and text search. - Finding details and remediation guidance. - The optional local Ollama model selector and explanation dialog. - JSON and Markdown report exports. 3. Understand how these components communicate with the scanner, reports, and Ollama client. 4. Identify any existing shared styling helpers and reusable widgets. 5. Report the files you intend to modify and the planned changes before implementing the redesign. Do not perform a broad rewrite. Reuse the existing architecture and working components. ## 2. Current problems to address The existing interface works, but it looks like a basic default Tkinter utility: - Plain gray background and default-looking controls. - Weak visual hierarchy and inconsistent spacing. - Project selection, scan controls, filters, AI controls, and export actions lack clear grouping. - Severity levels are displayed as plain text. - Findings table is visually dense. - Finding details use a plain monospaced text area with insufficient visual organization. - The local AI experience looks disconnected from the main application. - The overall interface needs a consistent, professional design. ## 3. Target design Create a modern, light-themed security workbench using a restrained palette: - Deep navy for branding and important structural elements. - White or very light gray for application surfaces. - A subtle blue accent for primary actions and selection. - Muted gray for secondary text and borders. - Carefully chosen semantic colors for severity levels. - Consistent typography, spacing, padding, and alignment. The result should look intentional and professional rather than flashy. Use the existing Tkinter stack. You may use `ttk` styles and reusable styling helpers. Do not introduce a web frontend or migrate to another GUI framework. Do not add third-party Python dependencies unless absolutely necessary. Prefer Python's standard library and existing project dependencies. ## 4. Implement these improvements ### A. Application header - Give the application a clear, polished title area. - Retain the SecureLocal AI name and a short description of its purpose. - Use consistent padding and typography. - Organize the interface into visually distinct sections. - Make the main window resize gracefully. ### B. Project selection and scanning - Group the project path, folder-selection button, and Scan Project action into a coherent section. - Make the primary scan action visually prominent. - Keep the selected path readable and avoid unnecessary horizontal clutter. - Preserve existing folder-selection and scanning behavior. - Retain appropriate disabled/loading states if already implemented. ### C. Severity summary cards After a scan, display compact summary cards for: - Total findings. - High severity. - Medium severity. - Low severity. If informational findings are represented in the existing data model, preserve and display their count appropriately without overcrowding the interface. Requirements: - Calculate counts from the actual current scan results. - Update the cards after every scan. - Handle clean scans and empty results correctly. - Do not invent or duplicate metrics. - Keep counts consistent with the active scan results, not merely the filtered table. ### D. Findings toolbar and table - Place severity filtering and text search in a clean toolbar. - Improve the table's row height, column widths, alignment, selection colors, and readability. - Use subtle alternating row backgrounds if compatible with the existing Treeview implementation. - Make severity easy to distinguish using restrained color styling or clear visual indicators. - Keep rule IDs, filenames, line numbers, and finding titles readable. - Preserve existing filtering, selection, sorting (if implemented), and finding-detail behavior. - Ensure the table handles long filenames and finding titles gracefully. - Make the table resize sensibly when the window is resized. - Avoid adding decorative columns that reduce useful information. ### E. Finding details and remediation Redesign the finding-details section into a clear, readable panel. Where the existing finding data supports it, distinguish: - Finding title. - Severity and rule ID. - File location and line number. - Why the issue matters. - Redacted evidence. - Confidence. - Remediation guidance. - Rule limitations. Use readable typography, consistent spacing, sensible text wrapping, and appropriate scrolling. Do not expose unredacted secrets or raw source code that the current implementation intentionally excludes. Preserve the existing finding-selection behavior and all existing detail information. ### F. Local AI experience Make the local AI controls feel integrated with the rest of the interface. - Clearly label the model selector. - Style the Explain Selected with Local AI action consistently with other buttons. - Preserve the existing model configuration and request flow. - Keep AI explanations clearly separate from deterministic scanner findings. - Retain a visible warning that AI-generated advice is unverified. - Ensure long responses remain readable and scrollable. - Preserve loading, timeout, unavailable-service, missing-model, and malformed-response error handling. - Do not suppress genuine errors or make the interface appear successful when the request fails. The Ollama client currently uses a 120-second request timeout. Preserve this configuration unless you discover a specific technical reason to change it. Do not send additional source code, project paths, or secrets to Ollama as part of the redesign. ### G. Report exports - Visually group the JSON and Markdown export actions. - Preserve the existing export behavior, file dialogs, output formats, and redaction safeguards. - Ensure the buttons remain accessible at different window sizes. ### H. Consistency and usability - Apply a consistent styling system across the application. - Use clear button states and readable text contrast. - Preserve keyboard and mouse usability. - Ensure all important controls remain visible or reachable when resizing the window. - Use scrollable containers where needed. - Avoid excessive nested frames, tiny fonts, excessive colors, and unnecessary decoration. - Do not rely on emoji as the primary visual language of a security tool. ## 5. Strict preservation requirements This is a visual redesign, not a scanner rewrite. **Do not:** - Change the seven existing security detection rules or their semantics. - Change finding IDs, severity logic, confidence logic, or evidence redaction. - Weaken endpoint validation or Ollama security controls. - Change scanner limits, file-discovery behavior, or symlink protections. - Modify report schemas or remove report metadata. - Execute or import scanned source files. - Remove existing functionality to simplify the layout. - Break asynchronous scanning or AI execution. - Introduce network calls, cloud AI services, automatic model downloads, or telemetry. - Modify project files outside the scope of the redesign without a clear reason. - Replace real functionality with mock data. - claim tests pass unless you actually run them and see the result. Preserve the current offline-first privacy model. ## 6. Implementation approach Work incrementally: 1. Inspect and map the existing UI implementation. 2. Explain the proposed file changes. 3. Implement the shared styles and main layou 
Agent
▸ view {"path":"c:\\Projects\\securelocal-ai\\README.md","view_range":[1,260]}
{ "path": "c:\\Projects\\securelocal-ai\\README.md", "view_range": [ 1, 260 ] }
 diff --git a/c:/Projects/securelocal-ai/README.md b/c:/Projects/securelocal-ai/README.md index 0000000..0000000 100644 --- a/c:/Projects/securelocal-ai/README.md +++ b/c:/Projects/securelocal-ai/README.md @@ -1,260 +1,260 @@ # SecureLocal AI **An offline-first Python code security auditor and remediation assistant.** SecureLocal AI is a desktop application that helps developers identify common security issues in Python source code without sending their source files to a cloud-based scanning service. It combines deterministic Abstract Syntax Tree (AST) analysis with optional, explicitly requested explanations from a locally running Ollama model. > **Disclaimer:** SecureLocal AI is an early-stage, heuristic security scanner. A clean scan does not prove that code is secure, and this tool does not replace manual code review or a professional security audit. ## Screenshots ### 1. Vulnerability Scan Displays detected security findings with rule IDs, severity levels, and source locations. ![Vulnerability scan](docs/screenshots/vulnerable-scan.png) ### 2. Clean Scan Demonstrates the scanner's behavior on a clean test fixture. ![Clean scan](docs/screenshots/clean-scan.png) ### 3. Finding Details and Remediation Shows finding evidence, explanations of potential risks, and recommended remediation steps. ![Finding details](docs/screenshots/finding-details.png) ### 4. Local AI Explanation Uses a locally running Ollama model to provide additional context and remediation advice for a selected finding. ![Local AI explanation](docs/screenshots/local-ai-explanation.png) ## Features - **Static Python analysis:** Uses the standard library and AST-based rules to inspect source code without importing or executing the target code. - **Seven security rules:** Detects potentially unsafe dynamic execution, insecure deserialization, risky shell execution, possible hardcoded credentials, weak hash algorithms, disabled HTTP TLS verification, and dynamically constructed SQL. - **Redacted evidence:** Masks recognized credential-like assignments, token formats, authorization values, and credentials embedded in common service URLs. - **Severity and filtering:** Presents findings with rule IDs, severity, locations, confidence, limitations, and remediation guidance, with severity and text filters in the desktop interface. - **Local AI assistance:** Offers optional explanations using an Ollama model running on the same machine. - **Report export:** Exports scan results to JSON and Markdown. - **Resource limits:** Applies file-count, file-size, total-byte, and finding limits to help control scanning workloads. - **Safer file discovery:** Skips common generated directories and symbolic links. - **Asynchronous desktop interface:** Uses Tkinter to keep scanning and AI explanation tasks from unnecessarily blocking the interface. - **No third-party Python dependencies:** The scanner, desktop interface, report exporters, and automated tests use Python's standard library. ## Technology Stack | Component | Technology | |---|---| | Language | Python 3.11+ | | Static analysis | Python AST | | Desktop GUI | Tkinter | | AI inference | Ollama with a locally installed model | | Report formats | JSON and Markdown | | Automated testing | `unittest` | | External Python dependencies | None | ## Requirements and Setup ### Requirements - Python 3.11 or newer. - A working Tkinter installation. - Windows is the primary documented setup environment. - Ollama and a locally installed model are optional and required only for AI explanations. ### Run the application Clone or download the repository and open a terminal in the project root. Check your Python installation: ```powershell python --version ``` Launch the desktop application: ```powershell python app.py ``` No `pip install` step is required for the scanner, GUI, exports, or tests. ### Run a scan 1. Launch the application. 2. Select the project directory you want to inspect. 3. Choose **Scan project**. 4. Review the findings, severity levels, and remediation guidance. 5. Select a finding to inspect its details. 6. Export the results to JSON or Markdown if needed. The current implementation scans Python (`.py`) files only. ### Run the automated tests From the project root: ```powershell python -m unittest discover -s tests -v ``` The current test suite contains **46 tests**, covering scanner behavior, security rules, redaction, report generation, Ollama client behavior, and GUI error handling. To run a syntax compilation check: ```powershell python -m compileall -q . ``` A successful compilation check produces no output. ### Run scanner smoke tests without the GUI Scan the included synthetic fixtures directly: ```powershell python -m scanner tests/fixtures/vulnerable python -m scanner tests/fixtures/clean ``` These fixtures help demonstrate expected behavior; they are not a comprehensive security benchmark. ## Architecture ```text securelocal-ai/ ├── ai/ Optional local Ollama client ├── scanner/ File discovery, AST rules, and scan engine ├── reports/ JSON and Markdown report exporters ├── ui/ Tkinter interface and finding details ├── tests/ Automated tests and synthetic fixtures ├── docs/ │ ├── SECURITY.md Threat model and data-flow notes │ └── screenshots/ Application screenshots ├── app.py Application entry point └── README.md ``` The scanner is responsible for producing findings independently of the AI component. The optional model provides supplementary explanations only; it does not determine severity, alter scan results, apply patches, or execute code. ## Security Rules | Rule ID | Detection | Important limitation | |---|---|---| | SLA001 | `eval()` and `exec()` | Does not establish whether the input is attacker-controlled. | | SLA002 | `pickle.load()`, `pickle.loads()`, and `Unpickler.load()` | Risk depends on whether serialized input is untrusted. | | SLA003 | `shell=True` in subprocess calls and dynamic `os.system`/`os.popen` use | Does not trace untrusted data into command arguments. | | SLA004 | Credential-like variable names assigned non-placeholder string literals | Heuristic; may miss secrets or flag non-secret values. Recognized evidence is redacted. | | SLA005 | MD5/SHA-1 hash calls | May flag legitimate non-security checksums. Password storage requires an appropriate password-hashing algorithm. | | SLA006 | `verify=False` in recognized `requests`/`httpx` calls | Other HTTP clients and verification patterns may not be recognized. | | SLA007 | SQL-looking text dynamically interpolated, formatted, or concatenated in execute calls | Cannot prove that input is untrusted or understand every database API. | These rules provide an initial set of checks, not comprehensive Static Application Security Testing (SAST) coverage. Findings must be reviewed in context. ## Optional Local AI Explanations SecureLocal AI can perform deterministic scans without Ollama. Local AI explanations are an optional enhancement. ### Setup 1. Install Ollama using its official installation instructions. 2. Ensure the Ollama service is running. 3. Download a model yourself if it is not already installed. For example: ```powershell ollama pull qwen2.5-coder:3b ``` This command is an optional manual setup step. SecureLocal AI does not download models automatically. 4. Launch SecureLocal AI, select a finding, and choose **Explain selected with local AI**. The default Ollama endpoint is: ```text http://127.0.0.1:11434 ``` The client restricts connections to the IPv4 loopback address `127.0.0.1` and rejects remote endpoints and redirects. Only a limited, redacted finding context is sent to Ollama after the user explicitly requests an explanation. The application does not send the entire project or source file to the model. AI-generated explanations are **unverified advice**. They can be incomplete, inaccurate, or unsuitable for the specific code and must be reviewed by a developer. ## Privacy and Threat Model SecureLocal AI is designed to minimiz 
Agent
▸ view {"path":"c:\\Projects\\securelocal-ai\\app.py","view_range":[1,220]}
{ "path": "c:\\Projects\\securelocal-ai\\app.py", "view_range": [ 1, 220 ] }
 diff --git a/c:/Projects/securelocal-ai/app.py b/c:/Projects/securelocal-ai/app.py index 0000000..0000000 100644 --- a/c:/Projects/securelocal-ai/app.py +++ b/c:/Projects/securelocal-ai/app.py @@ -1,220 +1,220 @@ from ui.main_window import run_app if __name__ == "__main__": run_app() 
Agent
▸ view {"path":"c:\\Projects\\securelocal-ai\\ui\\main_window.py","view_range":[1,420]}
{ "path": "c:\\Projects\\securelocal-ai\\ui\\main_window.py", "view_range": [ 1, 420 ] }
 diff --git a/c:/Projects/securelocal-ai/ui/main_window.py b/c:/Projects/securelocal-ai/ui/main_window.py index 0000000..0000000 100644 --- a/c:/Projects/securelocal-ai/ui/main_window.py +++ b/c:/Projects/securelocal-ai/ui/main_window.py @@ -1,420 +1,420 @@ from __future__ import annotations import queue import threading import tkinter as tk from pathlib import Path from tkinter import filedialog, messagebox, ttk from ai.ollama_client import DEFAULT_MODEL, OllamaClient, OllamaError from reports.exporter import export_json, export_markdown from scanner.engine import scan_project from scanner.models import Finding, ScanResult, Severity from ui.finding_details import FindingDetails class SecureLocalApp: def __init__(self, root: tk.Tk) -> None: self.root = root self.root.title("SecureLocal AI — Code Security Auditor") self.root.geometry("1120x780") self.root.minsize(860, 600) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) self.events: queue.Queue[tuple[str, object]] = queue.Queue() self.result: ScanResult | None = None self.findings_by_id: dict[str, Finding] = {} self._configure_style() self._build_ui() self.root.after(100, self._process_events) def _configure_style(self) -> None: style = ttk.Style(self.root) style.configure("AppTitle.TLabel", font=("Segoe UI", 19, "bold")) style.configure("Section.TLabel", font=("Segoe UI", 11, "bold")) style.configure("Privacy.TLabel", foreground="#245c3b") style.configure("Treeview", rowheight=25) def _build_ui(self) -> None: container = ttk.Frame(self.root, padding=16) container.grid(row=0, column=0, sticky="nsew") container.columnconfigure(0, weight=1) container.rowconfigure(4, weight=1) header = ttk.Frame(container) header.grid(row=0, column=0, sticky="ew") header.columnconfigure(0, weight=1) ttk.Label(header, text="SecureLocal AI", style="AppTitle.TLabel").grid( row=0, column=0, sticky="w" ) ttk.Label( header, text="Python code security checks that run on this device.", style="Privacy.TLabel", ).grid(row=1, column=0, sticky="w", pady=(3, 0)) folder_frame = ttk.LabelFrame(container, text="Project folder", padding=10) folder_frame.grid(row=1, column=0, sticky="ew", pady=(14, 8)) folder_frame.columnconfigure(0, weight=1) self.project_path = tk.StringVar() ttk.Entry(folder_frame, textvariable=self.project_path).grid( row=0, column=0, sticky="ew", padx=(0, 8) ) ttk.Button(folder_frame, text="Choose folder…", command=self._choose_folder).grid( row=0, column=1, padx=(0, 8) ) self.scan_button = ttk.Button(folder_frame, text="Scan project", command=self._start_scan) self.scan_button.grid(row=0, column=2) toolbar = ttk.Frame(container) toolbar.grid(row=2, column=0, sticky="ew", pady=6) ttk.Label(toolbar, text="Filter severity").pack(side="left") self.severity_filter = tk.StringVar(value="All") self.severity_combo = ttk.Combobox( toolbar, textvariable=self.severity_filter, state="readonly", values=("All", *(severity.value for severity in Severity)), width=12, ) self.severity_combo.pack(side="left", padx=(6, 14)) self.severity_combo.bind("<<ComboboxSelected>>", self._apply_filters) ttk.Label(toolbar, text="Search").pack(side="left") self.search_text = tk.StringVar() search = ttk.Entry(toolbar, textvariable=self.search_text, width=24) search.pack(side="left", padx=6) self.search_text.trace_add("write", self._apply_filters) self.summary = ttk.Label(toolbar, text="Choose a project folder to begin.") self.summary.pack(side="left", padx=(10, 0)) actions = ttk.Frame(container) actions.grid(row=3, column=0, sticky="ew", pady=(0, 8)) self.ai_model = tk.StringVar(value=DEFAULT_MODEL) ttk.Label(actions, text="Local model").pack(side="left") ttk.Entry(actions, textvariable=self.ai_model, width=22).pack(side="left", padx=6) self.explain_button = ttk.Button( actions, text="Explain selected with local AI", command=self._explain_selected, state="disabled", ) self.explain_button.pack(side="left", padx=(2, 12)) self.export_json_button = ttk.Button( actions, text="Export JSON…", command=self._export_json, state="disabled" ) self.export_json_button.pack(side="right", padx=(6, 0)) self.export_md_button = ttk.Button( actions, text="Export Markdown…", command=self._export_markdown, state="disabled" ) self.export_md_button.pack(side="right") content = ttk.Panedwindow(container, orient="vertical") content.grid(row=4, column=0, sticky="nsew") table_frame = ttk.Frame(content) table_frame.columnconfigure(0, weight=1) table_frame.rowconfigure(0, weight=1) columns = ("severity", "rule", "file", "line", "title") self.table = ttk.Treeview(table_frame, columns=columns, show="headings", selectmode="browse") for column, heading, width in ( ("severity", "Severity", 100), ("rule", "Rule", 85), ("file", "File", 280), ("line", "Line", 65), ("title", "Finding", 340), ): self.table.heading(column, text=heading) self.table.column(column, width=width, anchor="w") self.table.grid(row=0, column=0, sticky="nsew") self.table.bind("<<TreeviewSelect>>", self._selection_changed) vertical = ttk.Scrollbar(table_frame, orient="vertical", command=self.table.yview) vertical.grid(row=0, column=1, sticky="ns") self.table.configure(yscrollcommand=vertical.set) horizontal = ttk.Scrollbar(table_frame, orient="horizontal", command=self.table.xview) horizontal.grid(row=1, column=0, sticky="ew") self.table.configure(xscrollcommand=horizontal.set) self.details = FindingDetails(content) content.add(table_frame, weight=3) content.add(self.details, weight=2) self.status = tk.StringVar( value="Scanning uses local deterministic rules. Source files are not changed or uploaded." ) ttk.Label(container, textvariable=self.status, wraplength=1050).grid( row=5, column=0, sticky="ew", pady=(8, 0) ) def _choose_folder(self) -> None: selected = filedialog.askdirectory(title="Choose a Python project folder") if selected: self.project_path.set(selected) def _start_scan(self) -> None: selected = self.project_path.get().strip() if not selected or not Path(selected).is_dir(): messagebox.showerror("Choose a project", "Select an existing project folder first.") return self.scan_button.configure(state="disabled") self.status.set("Scanning Python files locally…") self.summary.configure(text="Scan in progress") self._clear_findings() thread = threading.Thread(target=self._scan_worker, args=(selected,), daemon=True) thread.start() def _scan_worker(self, selected: str) -> None: try: self.events.put(("scan", scan_project(selected))) except (OSError, ValueError, RecursionError) as error: self.events.put(("error", str(error))) def _process_events(self) -> None: try: while True: event, payload = self.events.get_nowait() if event == "scan": if isinstance(payload, ScanResult): self._show_result(payload) elif event == "explanation": if isinstance(payload, tuple) and len(payload) == 2: self._show_explanation(payload) elif event == "error": self 
Agent
▸ view {"path":"c:\\Projects\\securelocal-ai\\ui\\finding_details.py","view_range":[...
{ "path": "c:\\Projects\\securelocal-ai\\ui\\finding_details.py", "view_range": [ 1, 260 ] }
 diff --git a/c:/Projects/securelocal-ai/ui/finding_details.py b/c:/Projects/securelocal-ai/ui/finding_details.py index 0000000..0000000 100644 --- a/c:/Projects/securelocal-ai/ui/finding_details.py +++ b/c:/Projects/securelocal-ai/ui/finding_details.py @@ -1,260 +1,260 @@ from __future__ import annotations import tkinter as tk from tkinter import ttk from scanner.models import Finding class FindingDetails(ttk.Frame): def __init__(self, master: tk.Misc) -> None: super().__init__(master, padding=(8, 6)) self.columnconfigure(0, weight=1) ttk.Label(self, text="Finding details", style="Section.TLabel").grid( row=0, column=0, sticky="w" ) self.content = tk.Text(self, height=10, wrap="word", state="disabled", borderwidth=0) self.content.grid(row=1, column=0, sticky="nsew", pady=(6, 0)) self.rowconfigure(1, weight=1) scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.content.yview) scrollbar.grid(row=1, column=1, sticky="ns", pady=(6, 0)) self.content.configure(yscrollcommand=scrollbar.set) def show_finding(self, finding: Finding | None) -> None: if finding is None: text = "Select a finding to see its explanation, evidence, limitations, and remediation." else: text = ( f"{finding.title} · {finding.severity.value} · {finding.rule_id}\n" f"{finding.file_path}:{finding.line}:{finding.column}\n\n" f"Why it matters\n{finding.description}\n\n" f"Redacted evidence\n{finding.evidence}\n\n" f"Confidence: {finding.confidence}\n" f"Limitations\n{finding.limitations}\n\n" f"Remediation\n{finding.remediation}" ) self.content.configure(state="normal") self.content.delete("1.0", "end") self.content.insert("1.0", text) self.content.configure(state="disabled") 
Agent
▸ view {"path":"c:\\Projects\\securelocal-ai\\ui\\main_window.py","view_range":[181,...
{ "path": "c:\\Projects\\securelocal-ai\\ui\\main_window.py", "view_range": [ 181, 420 ] }
 diff --git a/c:/Projects/securelocal-ai/ui/main_window.py b/c:/Projects/securelocal-ai/ui/main_window.py index 0000000..0000000 100644 --- a/c:/Projects/securelocal-ai/ui/main_window.py +++ b/c:/Projects/securelocal-ai/ui/main_window.py @@ -181,240 +181,240 @@ self.status.set("The operation could not be completed.") messagebox.showerror("SecureLocal AI", str(payload)) except queue.Empty: pass self.root.after(100, self._process_events) def _show_result(self, result: ScanResult) -> None: self.result = result self.scan_button.configure(state="normal") self.export_json_button.configure(state="normal") self.export_md_button.configure(state="normal") self._populate_findings() counts = result.counts_by_severity self.summary.configure( text=( f"{result.files_scanned} files scanned · " f"{counts['Critical']} critical · {counts['High']} high · " f"{counts['Medium']} medium · {counts['Low']} low · {counts['Info']} info" ) ) skipped_note = f" {len(result.skipped_files)} file(s) skipped." if result.skipped_files else "" limit_note = " A safety limit was reached; this scan may be incomplete." if result.truncated else "" self.status.set( f"Scan complete. Findings are deterministic; no files were changed or uploaded." f"{skipped_note}{limit_note}" ) def _populate_findings(self) -> None: for item in self.table.get_children(): self.table.delete(item) self.findings_by_id.clear() if self.result is None: return for index, finding in enumerate(self.result.findings): item_id = f"finding-{index}" self.findings_by_id[item_id] = finding self.table.insert( "", "end", iid=item_id, values=( finding.severity.value, finding.rule_id, finding.file_path, finding.line, finding.title, ), ) self._apply_filters() def _apply_filters(self, *_: object) -> None: query = self.search_text.get().strip().casefold() severity = self.severity_filter.get() for item_id, finding in self.findings_by_id.items(): matches_severity = severity == "All" or finding.severity.value == severity haystack = " ".join( (finding.rule_id, finding.title, finding.file_path, finding.evidence) ).casefold() visible = matches_severity and query in haystack if visible and not self.table.exists(item_id): self.table.reattach(item_id, "", "end") elif not visible and self.table.exists(item_id): self.table.detach(item_id) def _selection_changed(self, _event: tk.Event) -> None: selected = self.table.selection() finding = self.findings_by_id.get(selected[0]) if selected else None self.details.show_finding(finding) self.explain_button.configure(state="normal" if finding else "disabled") def _clear_findings(self) -> None: self.result = None self.findings_by_id.clear() for item in self.table.get_children(): self.table.delete(item) self.details.show_finding(None) self.explain_button.configure(state="disabled") self.export_json_button.configure(state="disabled") self.export_md_button.configure(state="disabled") def _explain_selected(self) -> None: selected = self.table.selection() if not selected: return finding = self.findings_by_id[selected[0]] model = self.ai_model.get().strip() self.explain_button.configure(state="disabled") self.status.set("Checking the local Ollama service and installed model…") thread = threading.Thread( target=self._explanation_worker, args=(finding, model), daemon=True ) thread.start() def _explanation_worker(self, finding: Finding, model: str) -> None: try: explanation = OllamaClient().explain_finding(finding, model) self.events.put(("explanation", (True, explanation))) except OllamaError as error: self.events.put(("explanation", (False, str(error)))) def _show_explanation(self, payload: tuple[bool, str]) -> None: success, text = payload self.explain_button.configure(state="normal" if self.table.selection() else "disabled") if success: dialog = tk.Toplevel(self.root) dialog.title("Local AI explanation — unverified advice") dialog.geometry("600x440") dialog.transient(self.root) frame = ttk.Frame(dialog, padding=12) frame.pack(fill="both", expand=True) ttk.Label( frame, text="AI-generated local explanation. It may be incorrect; confirm findings independently.", wraplength=560, ).pack(anchor="w", pady=(0, 8)) content = tk.Text(frame, wrap="word") content.pack(fill="both", expand=True) content.insert("1.0", text) content.configure(state="disabled") scrollbar = ttk.Scrollbar(frame, orient="vertical", command=content.yview) scrollbar.pack(side="right", fill="y") content.configure(yscrollcommand=scrollbar.set) ttk.Button(dialog, text="Close", command=dialog.destroy).pack(pady=8) self.status.set("Local AI explanation received. Deterministic findings were not changed.") else: self.status.set("Local AI explanation unavailable; built-in remediation remains available.") messagebox.showinfo("Local AI unavailable", str(text)) def _export_json(self) -> None: self._export("json") def _export_markdown(self) -> None: self._export("markdown") def _export(self, format_name: str) -&g...
Source:https://dev.to/kushal_521a39b0824ba2b9e1/securelocal-ai-a-local-first-python-security-auditor-for-hacktoberfest-week-2-a90

Related posts