feat: add floating help chat widget, remove settings page #51
120
README.md
@@ -28,9 +28,9 @@
|
||||
|
||||
## About
|
||||
|
||||
Compliance Scanner is an autonomous agent that continuously monitors git repositories for security vulnerabilities, GDPR/OAuth compliance patterns, and dependency risks. It creates issues in external trackers (GitHub/GitLab/Jira) with evidence and remediation suggestions, reviews pull requests, and exposes a Dioxus-based dashboard for visualization.
|
||||
Compliance Scanner is an autonomous agent that continuously monitors git repositories for security vulnerabilities, GDPR/OAuth compliance patterns, and dependency risks. It creates issues in external trackers (GitHub/GitLab/Jira/Gitea) with evidence and remediation suggestions, reviews pull requests with multi-pass LLM analysis, runs autonomous penetration tests, and exposes a Dioxus-based dashboard for visualization.
|
||||
|
||||
> **How it works:** The agent runs as a lazy daemon -- it only scans when new commits are detected, triggered by cron schedules or webhooks. LLM-powered triage filters out false positives and generates actionable remediation.
|
||||
> **How it works:** The agent runs as a lazy daemon -- it only scans when new commits are detected, triggered by cron schedules or webhooks. LLM-powered triage filters out false positives and generates actionable remediation with multi-language awareness.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -41,31 +41,38 @@ Compliance Scanner is an autonomous agent that continuously monitors git reposit
|
||||
| **CVE Monitoring** | OSV.dev batch queries, NVD CVSS enrichment, SearXNG context |
|
||||
| **GDPR Patterns** | Detect PII logging, missing consent, hardcoded retention, missing deletion |
|
||||
| **OAuth Patterns** | Detect implicit grant, missing PKCE, token in localStorage, token in URLs |
|
||||
| **LLM Triage** | Confidence scoring via LiteLLM to filter false positives |
|
||||
| **Issue Creation** | Auto-create issues in GitHub, GitLab, or Jira with code evidence |
|
||||
| **PR Reviews** | Post security review comments on pull requests |
|
||||
| **Dashboard** | Fullstack Dioxus UI with findings, SBOM, issues, and statistics |
|
||||
| **Webhooks** | GitHub (HMAC-SHA256) and GitLab webhook receivers for push/PR events |
|
||||
| **LLM Triage** | Multi-language-aware confidence scoring (Rust, Python, Go, Java, Ruby, PHP, C++) |
|
||||
| **Issue Creation** | Auto-create issues in GitHub, GitLab, Jira, or Gitea with dedup via fingerprints |
|
||||
| **PR Reviews** | Multi-pass security review (logic, security, convention, complexity) with dedup |
|
||||
| **DAST Scanning** | Black-box security testing with endpoint discovery and parameter fuzzing |
|
||||
| **AI Pentesting** | Autonomous LLM-orchestrated penetration testing with encrypted reports |
|
||||
| **Code Graph** | Interactive code knowledge graph with impact analysis |
|
||||
| **AI Chat (RAG)** | Natural language Q&A grounded in repository source code |
|
||||
| **Help Assistant** | Documentation-grounded help chat accessible from every dashboard page |
|
||||
| **MCP Server** | Expose live security data to Claude, Cursor, and other AI tools |
|
||||
| **Dashboard** | Fullstack Dioxus UI with findings, SBOM, issues, DAST, pentest, and graph |
|
||||
| **Webhooks** | GitHub, GitLab, and Gitea webhook receivers for push/PR events |
|
||||
| **Finding Dedup** | SHA-256 fingerprint dedup for SAST, CWE-based dedup for DAST findings |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Cargo Workspace │
|
||||
├──────────────┬──────────────────┬───────────────────────────┤
|
||||
│ compliance- │ compliance- │ compliance- │
|
||||
│ core │ agent │ dashboard │
|
||||
│ (lib) │ (bin) │ (bin, Dioxus 0.7.3) │
|
||||
│ │ │ │
|
||||
│ Models │ Scan Pipeline │ Fullstack Web UI │
|
||||
│ Traits │ LLM Client │ Server Functions │
|
||||
│ Config │ Issue Trackers │ Charts + Tables │
|
||||
│ Errors │ Scheduler │ Settings Page │
|
||||
│ │ REST API │ │
|
||||
│ │ Webhooks │ │
|
||||
└──────────────┴──────────────────┴───────────────────────────┘
|
||||
│
|
||||
MongoDB (shared)
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ Cargo Workspace │
|
||||
├──────────────┬──────────────────┬──────────────┬──────────┬─────────────┤
|
||||
│ compliance- │ compliance- │ compliance- │ complian-│ compliance- │
|
||||
│ core (lib) │ agent (bin) │ dashboard │ ce-graph │ mcp (bin) │
|
||||
│ │ │ (bin) │ (lib) │ │
|
||||
│ Models │ Scan Pipeline │ Dioxus 0.7 │ Tree- │ MCP Server │
|
||||
│ Traits │ LLM Client │ Fullstack UI │ sitter │ Live data │
|
||||
│ Config │ Issue Trackers │ Help Chat │ Graph │ for AI │
|
||||
│ Errors │ Pentest Engine │ Server Fns │ Embedds │ tools │
|
||||
│ │ DAST Tools │ │ RAG │ │
|
||||
│ │ REST API │ │ │ │
|
||||
│ │ Webhooks │ │ │ │
|
||||
└──────────────┴──────────────────┴──────────────┴──────────┴─────────────┘
|
||||
│
|
||||
MongoDB (shared)
|
||||
```
|
||||
|
||||
## Scan Pipeline (7 Stages)
|
||||
@@ -84,11 +91,16 @@ Compliance Scanner is an autonomous agent that continuously monitors git reposit
|
||||
|-------|-----------|
|
||||
| Shared Library | `compliance-core` -- models, traits, config |
|
||||
| Agent | Axum REST API, git2, tokio-cron-scheduler, Semgrep, Syft |
|
||||
| Dashboard | Dioxus 0.7.3 fullstack, Tailwind CSS |
|
||||
| Dashboard | Dioxus 0.7.3 fullstack, Tailwind CSS 4 |
|
||||
| Code Graph | `compliance-graph` -- tree-sitter parsing, embeddings, RAG |
|
||||
| MCP Server | `compliance-mcp` -- Model Context Protocol for AI tools |
|
||||
| DAST | `compliance-dast` -- dynamic application security testing |
|
||||
| Database | MongoDB with typed collections |
|
||||
| LLM | LiteLLM (OpenAI-compatible API) |
|
||||
| Issue Trackers | GitHub (octocrab), GitLab (REST v4), Jira (REST v3) |
|
||||
| LLM | LiteLLM (OpenAI-compatible API for chat, triage, embeddings) |
|
||||
| Issue Trackers | GitHub (octocrab), GitLab (REST v4), Jira (REST v3), Gitea |
|
||||
| CVE Sources | OSV.dev, NVD, SearXNG |
|
||||
| Auth | Keycloak (OAuth2/PKCE, SSO) |
|
||||
| Browser Automation | Chromium (headless, for pentesting and PDF generation) |
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -151,20 +163,35 @@ The agent exposes a REST API on port 3001:
|
||||
| `GET` | `/api/v1/sbom` | List dependencies |
|
||||
| `GET` | `/api/v1/issues` | List cross-tracker issues |
|
||||
| `GET` | `/api/v1/scan-runs` | Scan execution history |
|
||||
| `GET` | `/api/v1/graph/:repo_id` | Code knowledge graph |
|
||||
|
|
||||
| `POST` | `/api/v1/graph/:repo_id/build` | Trigger graph build |
|
||||
| `GET` | `/api/v1/dast/targets` | List DAST targets |
|
||||
| `POST` | `/api/v1/dast/targets` | Add DAST target |
|
||||
| `GET` | `/api/v1/dast/findings` | List DAST findings |
|
||||
| `POST` | `/api/v1/chat/:repo_id` | RAG-powered code chat |
|
||||
| `POST` | `/api/v1/help/chat` | Documentation-grounded help chat |
|
||||
|
sharang
commented
[medium] Missing type annotations in API documentation New API endpoints like '/api/v1/chat/:repo_id' and '/api/v1/help/chat' lack type information in their documentation, which could lead to confusion about expected request/response formats. This pattern appears inconsistent with typical API documentation practices in the project. Suggested fix: Include example request/response schemas for new API endpoints to ensure consistency with established documentation patterns *Scanner: code-review/convention | * **[medium] Missing type annotations in API documentation**
New API endpoints like '/api/v1/chat/:repo_id' and '/api/v1/help/chat' lack type information in their documentation, which could lead to confusion about expected request/response formats. This pattern appears inconsistent with typical API documentation practices in the project.
Suggested fix: Include example request/response schemas for new API endpoints to ensure consistency with established documentation patterns
*Scanner: code-review/convention | *
<!-- compliance-fp:ecd94b50362c284ac987aeda4a192f6c34e295f0dc50bb5316f9a39cb3cacc8d -->
|
||||
| `POST` | `/api/v1/pentest/sessions` | Create pentest session |
|
||||
| `POST` | `/api/v1/pentest/sessions/:id/export` | Export encrypted pentest report |
|
||||
| `POST` | `/webhook/github` | GitHub webhook (HMAC-SHA256) |
|
||||
| `POST` | `/webhook/gitlab` | GitLab webhook (token verify) |
|
||||
| `POST` | `/webhook/gitea` | Gitea webhook |
|
||||
|
||||
## Dashboard Pages
|
||||
|
||||
| Page | Description |
|
||||
|------|-------------|
|
||||
| **Overview** | Stat cards, severity distribution chart |
|
||||
| **Repositories** | Add/manage tracked repos, trigger scans |
|
||||
| **Findings** | Filterable table by severity, type, status |
|
||||
| **Overview** | Stat cards, severity distribution, AI chat cards, MCP status |
|
||||
| **Repositories** | Add/manage tracked repos, trigger scans, webhook config |
|
||||
| **Findings** | Filterable table by severity, type, status, scanner |
|
||||
| **Finding Detail** | Code evidence, remediation, suggested fix, linked issue |
|
||||
| **SBOM** | Dependency inventory with vulnerability badges |
|
||||
| **Issues** | Cross-tracker view (GitHub + GitLab + Jira) |
|
||||
| **Settings** | Configure LiteLLM, tracker tokens, SearXNG URL |
|
||||
| **SBOM** | Dependency inventory with vulnerability badges, license summary |
|
||||
| **Issues** | Cross-tracker view (GitHub + GitLab + Jira + Gitea) |
|
||||
| **Code Graph** | Interactive architecture visualization, impact analysis |
|
||||
| **AI Chat** | RAG-powered Q&A about repository code |
|
||||
| **DAST** | Dynamic scanning targets, findings, and scan history |
|
||||
| **Pentest** | AI-driven pentest sessions, attack chain visualization |
|
||||
| **MCP Servers** | Model Context Protocol server management |
|
||||
| **Help Chat** | Floating assistant (available on every page) for product Q&A |
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -173,19 +200,24 @@ compliance-scanner/
|
||||
├── compliance-core/ Shared library (models, traits, config, errors)
|
||||
├── compliance-agent/ Agent daemon (pipeline, LLM, trackers, API, webhooks)
|
||||
│ └── src/
|
||||
│ ├── pipeline/ 7-stage scan pipeline
|
||||
│ ├── llm/ LiteLLM client, triage, descriptions, fixes, PR review
|
||||
│ ├── trackers/ GitHub, GitLab, Jira integrations
|
||||
│ ├── api/ REST API (Axum)
|
||||
│ └── webhooks/ GitHub + GitLab webhook receivers
|
||||
│ ├── pipeline/ 7-stage scan pipeline, dedup, PR reviews, code review
|
||||
│ ├── llm/ LiteLLM client, triage, descriptions, fixes, review prompts
|
||||
│ ├── trackers/ GitHub, GitLab, Jira, Gitea integrations
|
||||
│ ├── pentest/ AI-driven pentest orchestrator, tools, reports
|
||||
│ ├── rag/ RAG pipeline, chunking, embedding
|
||||
│ ├── api/ REST API (Axum), help chat
|
||||
│ └── webhooks/ GitHub, GitLab, Gitea webhook receivers
|
||||
├── compliance-dashboard/ Dioxus fullstack dashboard
|
||||
│ └── src/
|
||||
│ ├── components/ Reusable UI components
|
||||
│ ├── infrastructure/ Server functions, DB, config
|
||||
│ └── pages/ Full page views
|
||||
│ ├── components/ Reusable UI (sidebar, help chat, attack chain, etc.)
|
||||
│ ├── infrastructure/ Server functions, DB, config, auth
|
||||
│ └── pages/ Full page views (overview, DAST, pentest, graph, etc.)
|
||||
├── compliance-graph/ Code knowledge graph (tree-sitter, embeddings, RAG)
|
||||
├── compliance-dast/ Dynamic application security testing
|
||||
├── compliance-mcp/ Model Context Protocol server
|
||||
├── docs/ VitePress documentation site
|
||||
├── assets/ Static assets (CSS, icons)
|
||||
├── styles/ Tailwind input stylesheet
|
||||
└── bin/ Dashboard binary entrypoint
|
||||
└── styles/ Tailwind input stylesheet
|
||||
```
|
||||
|
||||
## External Services
|
||||
@@ -193,10 +225,12 @@ compliance-scanner/
|
||||
| Service | Purpose | Default URL |
|
||||
|---------|---------|-------------|
|
||||
| MongoDB | Persistence | `mongodb://localhost:27017` |
|
||||
| LiteLLM | LLM proxy for triage and generation | `http://localhost:4000` |
|
||||
| LiteLLM | LLM proxy (chat, triage, embeddings) | `http://localhost:4000` |
|
||||
| SearXNG | CVE context search | `http://localhost:8888` |
|
||||
| Keycloak | Authentication (OAuth2/PKCE, SSO) | `http://localhost:8080` |
|
||||
| Semgrep | SAST scanning | CLI tool |
|
||||
| Syft | SBOM generation | CLI tool |
|
||||
| Chromium | Headless browser (pentesting, PDF) | Managed via Docker |
|
||||
|
||||
---
|
||||
|
||||
|
||||
187
compliance-agent/src/api/handlers/help_chat.rs
Normal file
@@ -0,0 +1,187 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use axum::extract::Extension;
|
||||
use axum::http::StatusCode;
|
||||
use axum::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use super::dto::{AgentExt, ApiResponse};
|
||||
|
||||
// ── DTOs ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct HelpChatMessage {
|
||||
pub role: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct HelpChatRequest {
|
||||
pub message: String,
|
||||
#[serde(default)]
|
||||
pub history: Vec<HelpChatMessage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct HelpChatResponse {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
|
sharang
commented
[medium] Unnecessary In Suggested fix: Ensure that *Scanner: code-review/logic | * **[medium] Unnecessary `unwrap_or` in `find_project_root`**
In `find_project_root`, the `current.pop()` call can return false when reaching the root directory, but the loop continues even after popping to the root. This may cause an infinite loop or unexpected behavior if `current.pop()` fails to pop further.
Suggested fix: Ensure that `current.pop()` is checked properly and that the loop terminates correctly when reaching the filesystem root.
*Scanner: code-review/logic | *
<!-- compliance-fp:02c4e9afc43ed9b395b629d0e82e35365829a885d31ce5db7e15af42341a9d9d -->
sharang
commented
[medium] Unnecessary In Suggested fix: Ensure that *Scanner: code-review/logic | * **[medium] Unnecessary `unwrap_or` in `find_project_root`**
In `find_project_root`, the `current.pop()` call can return false when reaching the root directory, but the loop continues even after popping to the root. This may cause an infinite loop or unexpected behavior if `current.pop()` fails to pop further.
Suggested fix: Ensure that `current.pop()` is checked properly and that the loop terminates correctly when reaching the filesystem root.
*Scanner: code-review/logic | *
<!-- compliance-fp:02c4e9afc43ed9b395b629d0e82e35365829a885d31ce5db7e15af42341a9d9d -->
|
||||
// ── Doc cache ────────────────────────────────────────────────────────────────
|
||||
|
||||
static DOC_CONTEXT: OnceLock<String> = OnceLock::new();
|
||||
|
||||
|
sharang
commented
[medium] Deeply nested control flow in doc loading The load_docs function has deeply nested control flow with multiple if/else branches and nested loops that make it difficult to follow the execution path. The function has 4 levels of nesting which increases complexity. Suggested fix: Refactor the function to reduce nesting by extracting inner logic into smaller helper functions. Consider early returns and reducing the number of nested conditions. *Scanner: code-review/complexity | * **[medium] Deeply nested control flow in doc loading**
The load_docs function has deeply nested control flow with multiple if/else branches and nested loops that make it difficult to follow the execution path. The function has 4 levels of nesting which increases complexity.
Suggested fix: Refactor the function to reduce nesting by extracting inner logic into smaller helper functions. Consider early returns and reducing the number of nested conditions.
*Scanner: code-review/complexity | *
<!-- compliance-fp:c4bd24f3a999317cadb959e821ddfd67b9403f6d80aad65a24aff7bd061b070c -->
sharang
commented
[medium] Deeply nested control flow in doc loading The load_docs function has deeply nested control flow with multiple if/else branches and nested loops that make it difficult to follow the execution path. The function has 4 levels of nesting which increases complexity. Suggested fix: Refactor the function to reduce nesting by extracting inner logic into smaller helper functions. Consider early returns and reducing the number of nested conditions. *Scanner: code-review/complexity | * **[medium] Deeply nested control flow in doc loading**
The load_docs function has deeply nested control flow with multiple if/else branches and nested loops that make it difficult to follow the execution path. The function has 4 levels of nesting which increases complexity.
Suggested fix: Refactor the function to reduce nesting by extracting inner logic into smaller helper functions. Consider early returns and reducing the number of nested conditions.
*Scanner: code-review/complexity | *
<!-- compliance-fp:c4bd24f3a999317cadb959e821ddfd67b9403f6d80aad65a24aff7bd061b070c -->
|
||||
/// Walk upward from `start` until we find a directory containing both
|
||||
/// `README.md` and a `docs/` subdirectory.
|
||||
fn find_project_root(start: &Path) -> Option<PathBuf> {
|
||||
let mut current = start.to_path_buf();
|
||||
loop {
|
||||
if current.join("README.md").is_file() && current.join("docs").is_dir() {
|
||||
return Some(current);
|
||||
}
|
||||
if !current.pop() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read README.md + all docs/**/*.md (excluding node_modules).
|
||||
fn load_docs(root: &Path) -> String {
|
||||
let mut parts: Vec<String> = Vec::new();
|
||||
|
sharang
commented
[high] Incorrect filtering of non-Markdown files The filter condition for Markdown files in Suggested fix: Change *Scanner: code-review/logic | * **[high] Incorrect filtering of non-Markdown files**
The filter condition for Markdown files in `load_docs` uses `!s.eq_ignore_ascii_case("md")`, which excludes files ending in `.md`. This is backwards - it should be `s.eq_ignore_ascii_case("md")` to include only Markdown files.
Suggested fix: Change `!s.eq_ignore_ascii_case("md")` to `s.eq_ignore_ascii_case("md")` to correctly filter for Markdown files.
*Scanner: code-review/logic | *
<!-- compliance-fp:0ca420b612297b382a3d12aaba34045c70b0b8a5c088abab4ea84d05306408c9 -->
sharang
commented
[high] Incorrect filtering of non-Markdown files The filter condition for Markdown files in Suggested fix: Change *Scanner: code-review/logic | * **[high] Incorrect filtering of non-Markdown files**
The filter condition for Markdown files in `load_docs` uses `!s.eq_ignore_ascii_case("md")`, which excludes files ending in `.md`. This is backwards - it should be `s.eq_ignore_ascii_case("md")` to include only Markdown files.
Suggested fix: Change `!s.eq_ignore_ascii_case("md")` to `s.eq_ignore_ascii_case("md")` to correctly filter for Markdown files.
*Scanner: code-review/logic | *
<!-- compliance-fp:0ca420b612297b382a3d12aaba34045c70b0b8a5c088abab4ea84d05306408c9 -->
|
||||
|
||||
// Root README first
|
||||
|
sharang
commented
[high] Path Traversal via Documentation Loading The help_chat handler loads documentation files from the filesystem based on project root detection. The Suggested fix: Add validation to ensure the discovered project root is within a safe, expected directory hierarchy. Consider restricting the search to a specific allowed base path or implementing additional checks to prevent traversal beyond intended directories. Scanner: code-review/security | CWE: CWE-22 **[high] Path Traversal via Documentation Loading**
The help_chat handler loads documentation files from the filesystem based on project root detection. The `find_project_root` function walks up the directory tree to find a directory containing README.md and docs/, but does not validate that the discovered root is within expected boundaries. This could allow an attacker to manipulate the file loading behavior by placing malicious files in unexpected locations, potentially leading to path traversal or arbitrary file reading.
Suggested fix: Add validation to ensure the discovered project root is within a safe, expected directory hierarchy. Consider restricting the search to a specific allowed base path or implementing additional checks to prevent traversal beyond intended directories.
*Scanner: code-review/security | CWE: CWE-22*
<!-- compliance-fp:76ac519157cdfbe6a67bcb4ceda65576a16dbf8d56d83b4c5b6d91b4131a804a -->
sharang
commented
[high] Path Traversal via Documentation Loading The help_chat handler loads documentation files from the filesystem based on project root detection. The Suggested fix: Add validation to ensure the discovered project root is within a safe, expected directory hierarchy. Consider restricting the search to a specific allowed base path or implementing additional checks to prevent traversal beyond intended directories. Scanner: code-review/security | CWE: CWE-22 **[high] Path Traversal via Documentation Loading**
The help_chat handler loads documentation files from the filesystem based on project root detection. The `find_project_root` function walks up the directory tree to find a directory containing README.md and docs/, but does not validate that the discovered root is within expected boundaries. This could allow an attacker to manipulate the file loading behavior by placing malicious files in unexpected locations, potentially leading to path traversal or arbitrary file reading.
Suggested fix: Add validation to ensure the discovered project root is within a safe, expected directory hierarchy. Consider restricting the search to a specific allowed base path or implementing additional checks to prevent traversal beyond intended directories.
*Scanner: code-review/security | CWE: CWE-22*
<!-- compliance-fp:76ac519157cdfbe6a67bcb4ceda65576a16dbf8d56d83b4c5b6d91b4131a804a -->
|
||||
if let Ok(content) = std::fs::read_to_string(root.join("README.md")) {
|
||||
parts.push(format!("<!-- file: README.md -->\n{content}"));
|
||||
|
sharang
commented
[medium] Complex boolean expression in file filtering The boolean expression in the filter_entry closure uses multiple nested conditions that are hard to follow. Specifically, the line checking for non-md files is complex and could be simplified. Suggested fix: Extract the file extension check into a separate helper function or simplify the boolean logic by breaking it into clear steps. Consider using a more readable pattern like: *Scanner: code-review/complexity | * **[medium] Complex boolean expression in file filtering**
The boolean expression in the filter_entry closure uses multiple nested conditions that are hard to follow. Specifically, the line checking for non-md files is complex and could be simplified.
Suggested fix: Extract the file extension check into a separate helper function or simplify the boolean logic by breaking it into clear steps. Consider using a more readable pattern like: `if path.extension().and_then(|s| s.to_str()).map(|s| s.eq_ignore_ascii_case("md")).unwrap_or(false) { continue; }`
*Scanner: code-review/complexity | *
<!-- compliance-fp:ad8f9646e3587f284240388c4901ec6201e1bcd3d5681aaa9ae83cb176d264f1 -->
sharang
commented
[medium] Complex boolean expression in file filtering The boolean expression in the filter_entry closure uses multiple nested conditions that are hard to follow. Specifically, the line checking for non-md files is complex and could be simplified. Suggested fix: Extract the file extension check into a separate helper function or simplify the boolean logic by breaking it into clear steps. Consider using a more readable pattern like: *Scanner: code-review/complexity | * **[medium] Complex boolean expression in file filtering**
The boolean expression in the filter_entry closure uses multiple nested conditions that are hard to follow. Specifically, the line checking for non-md files is complex and could be simplified.
Suggested fix: Extract the file extension check into a separate helper function or simplify the boolean logic by breaking it into clear steps. Consider using a more readable pattern like: `if path.extension().and_then(|s| s.to_str()).map(|s| s.eq_ignore_ascii_case("md")).unwrap_or(false) { continue; }`
*Scanner: code-review/complexity | *
<!-- compliance-fp:ad8f9646e3587f284240388c4901ec6201e1bcd3d5681aaa9ae83cb176d264f1 -->
|
||||
}
|
||||
|
||||
// docs/**/*.md, skipping node_modules
|
||||
for entry in WalkDir::new(root.join("docs"))
|
||||
.follow_links(false)
|
||||
.into_iter()
|
||||
.filter_entry(|e| {
|
||||
!e.path()
|
||||
.components()
|
||||
.any(|c| c.as_os_str() == "node_modules")
|
||||
})
|
||||
|
sharang
commented
[medium] Potential panic in doc loading due to unwrap usage The load_docs function uses unwrap_or(path) which can panic if strip_prefix fails. While this is unlikely, it's an unsafe pattern that could crash the application if the path manipulation logic breaks unexpectedly. Suggested fix: Replace unwrap_or with a more graceful fallback or handle the error case explicitly to prevent potential panics. *Scanner: code-review/convention | * **[medium] Potential panic in doc loading due to unwrap usage**
The load_docs function uses unwrap_or(path) which can panic if strip_prefix fails. While this is unlikely, it's an unsafe pattern that could crash the application if the path manipulation logic breaks unexpectedly.
Suggested fix: Replace unwrap_or with a more graceful fallback or handle the error case explicitly to prevent potential panics.
*Scanner: code-review/convention | *
<!-- compliance-fp:33a93c3ba7d2c1d88504a0a70e9686ca0dfe7940315a51df9ccb2dfb3c7b9ca6 -->
sharang
commented
[medium] Potential panic in doc loading due to unwrap usage The load_docs function uses unwrap_or(path) which can panic if strip_prefix fails. While this is unlikely, it's an unsafe pattern that could crash the application if the path manipulation logic breaks unexpectedly. Suggested fix: Replace unwrap_or with a more graceful fallback or handle the error case explicitly to prevent potential panics. *Scanner: code-review/convention | * **[medium] Potential panic in doc loading due to unwrap usage**
The load_docs function uses unwrap_or(path) which can panic if strip_prefix fails. While this is unlikely, it's an unsafe pattern that could crash the application if the path manipulation logic breaks unexpectedly.
Suggested fix: Replace unwrap_or with a more graceful fallback or handle the error case explicitly to prevent potential panics.
*Scanner: code-review/convention | *
<!-- compliance-fp:33a93c3ba7d2c1d88504a0a70e9686ca0dfe7940315a51df9ccb2dfb3c7b9ca6 -->
|
||||
.filter_map(|e| e.ok())
|
||||
{
|
||||
|
sharang
commented
[high] Potential panic in In the Suggested fix: Replace *Scanner: code-review/logic | * **[high] Potential panic in `load_docs` when stripping path prefix**
In the `load_docs` function, `path.strip_prefix(root).unwrap_or(path)` can panic if `root` is not a prefix of `path`. This happens when `path` is outside the `root` directory, which shouldn't occur given the filtering logic, but there's a potential race condition or incorrect assumption that could lead to this.
Suggested fix: Replace `unwrap_or(path)` with a safe fallback like `path.to_string_lossy().to_string()` or handle the error case explicitly to avoid potential panics.
*Scanner: code-review/logic | *
<!-- compliance-fp:e5836684030a2c1c30386e706014304fbe23361a6a162ae6806a15eebcc3487f -->
sharang
commented
[high] Potential panic in In the Suggested fix: Replace *Scanner: code-review/logic | * **[high] Potential panic in `load_docs` when stripping path prefix**
In the `load_docs` function, `path.strip_prefix(root).unwrap_or(path)` can panic if `root` is not a prefix of `path`. This happens when `path` is outside the `root` directory, which shouldn't occur given the filtering logic, but there's a potential race condition or incorrect assumption that could lead to this.
Suggested fix: Replace `unwrap_or(path)` with a safe fallback like `path.to_string_lossy().to_string()` or handle the error case explicitly to avoid potential panics.
*Scanner: code-review/logic | *
<!-- compliance-fp:e5836684030a2c1c30386e706014304fbe23361a6a162ae6806a15eebcc3487f -->
|
||||
let path = entry.path();
|
||||
if !path.is_file() {
|
||||
continue;
|
||||
}
|
||||
|
sharang
commented
[medium] Insecure File Reading with Potential Directory Traversal The Suggested fix: Implement stricter path validation to ensure all files being read are within the documented 'docs/' directory. Add checks to prevent reading files outside of the intended scope, such as verifying that the absolute path of each file is within the docs directory. Scanner: code-review/security | CWE: CWE-22 **[medium] Insecure File Reading with Potential Directory Traversal**
The `load_docs` function reads all .md files from the 'docs/' directory recursively. While it filters out node_modules, it doesn't validate that the paths being read are within the intended documentation directory. An attacker could potentially place malicious markdown files in unexpected locations that would be included in the documentation context, leading to potential information disclosure or injection attacks.
Suggested fix: Implement stricter path validation to ensure all files being read are within the documented 'docs/' directory. Add checks to prevent reading files outside of the intended scope, such as verifying that the absolute path of each file is within the docs directory.
*Scanner: code-review/security | CWE: CWE-22*
<!-- compliance-fp:21f3c58b8f7736cc2c05d1d759dab510ebbd6d4b1e078fdf812ec14c2e2ba42a -->
sharang
commented
[medium] Insecure File Reading with Potential Directory Traversal The Suggested fix: Implement stricter path validation to ensure all files being read are within the documented 'docs/' directory. Add checks to prevent reading files outside of the intended scope, such as verifying that the absolute path of each file is within the docs directory. Scanner: code-review/security | CWE: CWE-22 **[medium] Insecure File Reading with Potential Directory Traversal**
The `load_docs` function reads all .md files from the 'docs/' directory recursively. While it filters out node_modules, it doesn't validate that the paths being read are within the intended documentation directory. An attacker could potentially place malicious markdown files in unexpected locations that would be included in the documentation context, leading to potential information disclosure or injection attacks.
Suggested fix: Implement stricter path validation to ensure all files being read are within the documented 'docs/' directory. Add checks to prevent reading files outside of the intended scope, such as verifying that the absolute path of each file is within the docs directory.
*Scanner: code-review/security | CWE: CWE-22*
<!-- compliance-fp:21f3c58b8f7736cc2c05d1d759dab510ebbd6d4b1e078fdf812ec14c2e2ba42a -->
|
||||
if path
|
||||
.extension()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(|s| !s.eq_ignore_ascii_case("md"))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
|
sharang
commented
[medium] Potential Information Disclosure Through File Content Exposure The help_chat handler includes file contents directly in the system prompt without sanitization. If any documentation file contains sensitive information (like API keys, passwords, or internal paths), this information could be exposed to the LLM and potentially leaked through responses. Additionally, the file inclusion mechanism could expose internal project structure details. Suggested fix: Consider implementing content filtering or sanitization before including file contents in prompts. Alternatively, implement a whitelist of allowed documentation files or add a mechanism to exclude sensitive content from being included in the context. Scanner: code-review/security | CWE: CWE-200 **[medium] Potential Information Disclosure Through File Content Exposure**
The help_chat handler includes file contents directly in the system prompt without sanitization. If any documentation file contains sensitive information (like API keys, passwords, or internal paths), this information could be exposed to the LLM and potentially leaked through responses. Additionally, the file inclusion mechanism could expose internal project structure details.
Suggested fix: Consider implementing content filtering or sanitization before including file contents in prompts. Alternatively, implement a whitelist of allowed documentation files or add a mechanism to exclude sensitive content from being included in the context.
*Scanner: code-review/security | CWE: CWE-200*
<!-- compliance-fp:013aff4509a775822b6f5e638262cc557f8f79ddb12ebc1416f36a4d461a3562 -->
sharang
commented
[medium] Potential Information Disclosure Through File Content Exposure The help_chat handler includes file contents directly in the system prompt without sanitization. If any documentation file contains sensitive information (like API keys, passwords, or internal paths), this information could be exposed to the LLM and potentially leaked through responses. Additionally, the file inclusion mechanism could expose internal project structure details. Suggested fix: Consider implementing content filtering or sanitization before including file contents in prompts. Alternatively, implement a whitelist of allowed documentation files or add a mechanism to exclude sensitive content from being included in the context. Scanner: code-review/security | CWE: CWE-200 **[medium] Potential Information Disclosure Through File Content Exposure**
The help_chat handler includes file contents directly in the system prompt without sanitization. If any documentation file contains sensitive information (like API keys, passwords, or internal paths), this information could be exposed to the LLM and potentially leaked through responses. Additionally, the file inclusion mechanism could expose internal project structure details.
Suggested fix: Consider implementing content filtering or sanitization before including file contents in prompts. Alternatively, implement a whitelist of allowed documentation files or add a mechanism to exclude sensitive content from being included in the context.
*Scanner: code-review/security | CWE: CWE-200*
<!-- compliance-fp:013aff4509a775822b6f5e638262cc557f8f79ddb12ebc1416f36a4d461a3562 -->
|
||||
continue;
|
||||
}
|
||||
|
||||
let rel = path.strip_prefix(root).unwrap_or(path);
|
||||
if let Ok(content) = std::fs::read_to_string(path) {
|
||||
parts.push(format!("<!-- file: {} -->\n{content}", rel.display()));
|
||||
}
|
||||
}
|
||||
|
||||
if parts.is_empty() {
|
||||
tracing::warn!(
|
||||
"help_chat: no documentation files found under {}",
|
||||
root.display()
|
||||
);
|
||||
} else {
|
||||
tracing::info!(
|
||||
"help_chat: loaded {} documentation file(s) from {}",
|
||||
parts.len(),
|
||||
root.display()
|
||||
);
|
||||
}
|
||||
|
||||
parts.join("\n\n---\n\n")
|
||||
}
|
||||
|
||||
/// Returns a reference to the cached doc context string, initialised on
|
||||
/// first call via `OnceLock`.
|
||||
fn doc_context() -> &'static str {
|
||||
DOC_CONTEXT.get_or_init(|| {
|
||||
let start = std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|p| p.parent().map(Path::to_path_buf))
|
||||
.unwrap_or_else(|| PathBuf::from("."));
|
||||
|
||||
match find_project_root(&start) {
|
||||
Some(root) => load_docs(&root),
|
||||
None => {
|
||||
// Fallback: try current working directory
|
||||
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
|
||||
if cwd.join("README.md").is_file() {
|
||||
return load_docs(&cwd);
|
||||
}
|
||||
tracing::error!(
|
||||
"help_chat: could not locate project root from {}; doc context will be empty",
|
||||
start.display()
|
||||
);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ── Handler ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/// POST /api/v1/help/chat — Answer questions about the compliance-scanner
|
||||
/// using the project documentation as grounding context.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn help_chat(
|
||||
Extension(agent): AgentExt,
|
||||
Json(req): Json<HelpChatRequest>,
|
||||
) -> Result<Json<ApiResponse<HelpChatResponse>>, StatusCode> {
|
||||
|
sharang
commented
[medium] Large function with multiple responsibilities The help_chat function is 40 lines long and handles multiple responsibilities: preparing the system prompt, building message history, calling the LLM, and constructing the response. This makes it harder to test and maintain. Suggested fix: Break this function into smaller, focused functions such as: prepare_system_prompt, build_message_history, call_llm, and construct_response. Each should have a single responsibility. *Scanner: code-review/complexity | * **[medium] Large function with multiple responsibilities**
The help_chat function is 40 lines long and handles multiple responsibilities: preparing the system prompt, building message history, calling the LLM, and constructing the response. This makes it harder to test and maintain.
Suggested fix: Break this function into smaller, focused functions such as: prepare_system_prompt, build_message_history, call_llm, and construct_response. Each should have a single responsibility.
*Scanner: code-review/complexity | *
<!-- compliance-fp:d2495cf0753085e348c9c35a8697cc1feb088a94dd8e0691ab79580d7708fd78 -->
sharang
commented
[medium] Large function with multiple responsibilities The help_chat function is 40 lines long and handles multiple responsibilities: preparing the system prompt, building message history, calling the LLM, and constructing the response. This makes it harder to test and maintain. Suggested fix: Break this function into smaller, focused functions such as: prepare_system_prompt, build_message_history, call_llm, and construct_response. Each should have a single responsibility. *Scanner: code-review/complexity | * **[medium] Large function with multiple responsibilities**
The help_chat function is 40 lines long and handles multiple responsibilities: preparing the system prompt, building message history, calling the LLM, and constructing the response. This makes it harder to test and maintain.
Suggested fix: Break this function into smaller, focused functions such as: prepare_system_prompt, build_message_history, call_llm, and construct_response. Each should have a single responsibility.
*Scanner: code-review/complexity | *
<!-- compliance-fp:d2495cf0753085e348c9c35a8697cc1feb088a94dd8e0691ab79580d7708fd78 -->
|
||||
let context = doc_context();
|
||||
|
||||
let system_prompt = if context.is_empty() {
|
||||
"You are a helpful assistant for the Compliance Scanner project. \
|
||||
Answer questions about how to use and configure it. \
|
||||
No documentation was loaded at startup, so rely on your general knowledge."
|
||||
.to_string()
|
||||
} else {
|
||||
format!(
|
||||
"You are a helpful assistant for the Compliance Scanner project. \
|
||||
Answer questions about how to use, configure, and understand it \
|
||||
using the documentation below as your primary source of truth.\n\n\
|
||||
Rules:\n\
|
||||
- Prefer information from the provided docs over general knowledge\n\
|
||||
- Quote or reference the relevant doc section when it helps\n\
|
||||
- If the docs do not cover the topic, say so clearly\n\
|
||||
- Be concise — lead with the answer, then explain if needed\n\
|
||||
- Use markdown formatting for readability\n\n\
|
||||
|
sharang
commented
[low] Missing type annotations on public API parameters The help_chat function signature lacks explicit type annotations for the Extension(agent) parameter, which makes it harder to maintain consistency with other handlers that likely follow a pattern of explicit typing. Suggested fix: Add explicit type annotation for the agent parameter: Extension(agent): Extension to match common patterns in the codebase. *Scanner: code-review/convention | * **[low] Missing type annotations on public API parameters**
The help_chat function signature lacks explicit type annotations for the Extension(agent) parameter, which makes it harder to maintain consistency with other handlers that likely follow a pattern of explicit typing.
Suggested fix: Add explicit type annotation for the agent parameter: Extension(agent): Extension<Agent> to match common patterns in the codebase.
*Scanner: code-review/convention | *
<!-- compliance-fp:dfbcb2c56d114d603c8929f65230df59505cc87e5aa8ed44720235e3f061e09d -->
sharang
commented
[low] Missing type annotations on public API parameters The help_chat function signature lacks explicit type annotations for the Extension(agent) parameter, which makes it harder to maintain consistency with other handlers that likely follow a pattern of explicit typing. Suggested fix: Add explicit type annotation for the agent parameter: Extension(agent): Extension to match common patterns in the codebase. *Scanner: code-review/convention | * **[low] Missing type annotations on public API parameters**
The help_chat function signature lacks explicit type annotations for the Extension(agent) parameter, which makes it harder to maintain consistency with other handlers that likely follow a pattern of explicit typing.
Suggested fix: Add explicit type annotation for the agent parameter: Extension(agent): Extension<Agent> to match common patterns in the codebase.
*Scanner: code-review/convention | *
<!-- compliance-fp:dfbcb2c56d114d603c8929f65230df59505cc87e5aa8ed44720235e3f061e09d -->
|
||||
## Project Documentation\n\n{context}"
|
||||
)
|
||||
};
|
||||
|
||||
let mut messages: Vec<(String, String)> = Vec::with_capacity(req.history.len() + 2);
|
||||
messages.push(("system".to_string(), system_prompt));
|
||||
|
||||
for msg in &req.history {
|
||||
messages.push((msg.role.clone(), msg.content.clone()));
|
||||
}
|
||||
messages.push(("user".to_string(), req.message));
|
||||
|
||||
let response_text = agent
|
||||
.llm
|
||||
.chat_with_messages(messages, Some(0.3))
|
||||
.await
|
||||
|
sharang
commented
[medium] Inconsistent error handling in help_chat handler The help_chat handler uses a mix of direct StatusCode returns and map_err with StatusCode::INTERNAL_SERVER_ERROR. This is inconsistent with typical error handling patterns where errors should be converted to a consistent error type or handled through a centralized error mechanism. Suggested fix: Consider implementing a proper error type for the API and use a consistent pattern like *Scanner: code-review/convention | * **[medium] Inconsistent error handling in help_chat handler**
The help_chat handler uses a mix of direct StatusCode returns and map_err with StatusCode::INTERNAL_SERVER_ERROR. This is inconsistent with typical error handling patterns where errors should be converted to a consistent error type or handled through a centralized error mechanism.
Suggested fix: Consider implementing a proper error type for the API and use a consistent pattern like `?` operator or explicit error conversion instead of mixing direct StatusCode returns with map_err.
*Scanner: code-review/convention | *
<!-- compliance-fp:3ac636a591d5f136305368cc0edb85cc7a2dfef26c63d4df46f15a9993d31db5 -->
sharang
commented
[medium] Inconsistent error handling in help_chat handler The help_chat handler uses a mix of direct StatusCode returns and map_err with StatusCode::INTERNAL_SERVER_ERROR. This is inconsistent with typical error handling patterns where errors should be converted to a consistent error type or handled through a centralized error mechanism. Suggested fix: Consider implementing a proper error type for the API and use a consistent pattern like *Scanner: code-review/convention | * **[medium] Inconsistent error handling in help_chat handler**
The help_chat handler uses a mix of direct StatusCode returns and map_err with StatusCode::INTERNAL_SERVER_ERROR. This is inconsistent with typical error handling patterns where errors should be converted to a consistent error type or handled through a centralized error mechanism.
Suggested fix: Consider implementing a proper error type for the API and use a consistent pattern like `?` operator or explicit error conversion instead of mixing direct StatusCode returns with map_err.
*Scanner: code-review/convention | *
<!-- compliance-fp:3ac636a591d5f136305368cc0edb85cc7a2dfef26c63d4df46f15a9993d31db5 -->
|
||||
.map_err(|e| {
|
||||
tracing::error!("LLM help chat failed: {e}");
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
|
||||
Ok(Json(ApiResponse {
|
||||
data: HelpChatResponse {
|
||||
message: response_text,
|
||||
},
|
||||
total: None,
|
||||
page: None,
|
||||
}))
|
||||
}
|
||||
@@ -4,6 +4,7 @@ pub mod dto;
|
||||
pub mod findings;
|
||||
pub mod graph;
|
||||
pub mod health;
|
||||
pub mod help_chat;
|
||||
pub mod issues;
|
||||
pub mod pentest_handlers;
|
||||
pub use pentest_handlers as pentest;
|
||||
|
||||
@@ -99,6 +99,8 @@ pub fn build_router() -> Router {
|
||||
"/api/v1/chat/{repo_id}/status",
|
||||
get(handlers::chat::embedding_status),
|
||||
)
|
||||
// Help chat (documentation-grounded Q&A)
|
||||
.route("/api/v1/help/chat", post(handlers::help_chat::help_chat))
|
||||
// Pentest API endpoints
|
||||
.route(
|
||||
"/api/v1/pentest/lookup-repo",
|
||||
|
||||
@@ -3645,3 +3645,205 @@ tbody tr:last-child td {
|
||||
.wizard-toggle.active .wizard-toggle-knob {
|
||||
transform: translateX(16px);
|
||||
}
|
||||
|
||||
|
sharang
commented
[medium] CSS file contains excessive new content The CSS file has gained 205 lines of new styling for the help chat widget, which significantly increases the file size and complexity. This makes maintenance harder and increases the risk of conflicts during future updates. Suggested fix: Consider extracting the help chat widget styles into a separate CSS file to keep the main stylesheet manageable and improve maintainability. *Scanner: code-review/complexity | * **[medium] CSS file contains excessive new content**
The CSS file has gained 205 lines of new styling for the help chat widget, which significantly increases the file size and complexity. This makes maintenance harder and increases the risk of conflicts during future updates.
Suggested fix: Consider extracting the help chat widget styles into a separate CSS file to keep the main stylesheet manageable and improve maintainability.
*Scanner: code-review/complexity | *
<!-- compliance-fp:2a42002bd10b88a77928c8ee255e103f5eb190358a906fa9147588f591af318b -->
sharang
commented
[medium] CSS file contains excessive new content The CSS file has gained 205 lines of new styling for the help chat widget, which significantly increases the file size and complexity. This makes maintenance harder and increases the risk of conflicts during future updates. Suggested fix: Consider extracting the help chat widget styles into a separate CSS file to keep the main stylesheet manageable and improve maintainability. *Scanner: code-review/complexity | * **[medium] CSS file contains excessive new content**
The CSS file has gained 205 lines of new styling for the help chat widget, which significantly increases the file size and complexity. This makes maintenance harder and increases the risk of conflicts during future updates.
Suggested fix: Consider extracting the help chat widget styles into a separate CSS file to keep the main stylesheet manageable and improve maintainability.
*Scanner: code-review/complexity | *
<!-- compliance-fp:2a42002bd10b88a77928c8ee255e103f5eb190358a906fa9147588f591af318b -->
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
HELP CHAT WIDGET
|
||||
Floating assistant for documentation Q&A
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
.help-chat-toggle {
|
||||
position: fixed;
|
||||
bottom: 24px;
|
||||
right: 28px;
|
||||
z-index: 50;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
color: var(--bg-primary);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4px 20px rgba(0, 200, 255, 0.3);
|
||||
transition: transform 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.help-chat-toggle:hover {
|
||||
transform: scale(1.08);
|
||||
box-shadow: 0 6px 28px rgba(0, 200, 255, 0.4);
|
||||
}
|
||||
|
||||
.help-chat-panel {
|
||||
position: fixed;
|
||||
bottom: 24px;
|
||||
right: 28px;
|
||||
z-index: 51;
|
||||
width: 400px;
|
||||
height: 520px;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-bright);
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.5), var(--accent-glow);
|
||||
}
|
||||
|
||||
.help-chat-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 18px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
.help-chat-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-family: 'Outfit', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.help-chat-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
}
|
||||
.help-chat-close:hover {
|
||||
color: var(--text-primary);
|
||||
background: var(--bg-elevated);
|
||||
}
|
||||
|
||||
.help-chat-messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.help-chat-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
font-size: 13px;
|
||||
gap: 8px;
|
||||
}
|
||||
.help-chat-hint {
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.help-msg {
|
||||
max-width: 88%;
|
||||
animation: helpMsgIn 0.15s ease-out;
|
||||
}
|
||||
@keyframes helpMsgIn {
|
||||
from { opacity: 0; transform: translateY(6px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.help-msg-user {
|
||||
align-self: flex-end;
|
||||
}
|
||||
.help-msg-assistant {
|
||||
align-self: flex-start;
|
||||
}
|
||||
.help-msg-content {
|
||||
padding: 10px 14px;
|
||||
border-radius: 12px;
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.help-msg-user .help-msg-content {
|
||||
background: var(--accent);
|
||||
color: var(--bg-primary);
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
.help-msg-assistant .help-msg-content {
|
||||
background: var(--bg-elevated);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--border);
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
.help-msg-assistant .help-msg-content code {
|
||||
background: rgba(0, 200, 255, 0.1);
|
||||
padding: 1px 5px;
|
||||
border-radius: 3px;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
.help-msg-loading {
|
||||
padding: 10px 14px;
|
||||
border-radius: 12px;
|
||||
background: var(--bg-elevated);
|
||||
border: 1px solid var(--border);
|
||||
border-bottom-left-radius: 4px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 13px;
|
||||
animation: helpPulse 1.2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes helpPulse {
|
||||
0%, 100% { opacity: 0.6; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
.help-chat-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 14px;
|
||||
border-top: 1px solid var(--border);
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
.help-chat-input input {
|
||||
flex: 1;
|
||||
background: var(--bg-elevated);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 10px 14px;
|
||||
color: var(--text-primary);
|
||||
font-size: 13px;
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
.help-chat-input input:focus {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.help-chat-input input::placeholder {
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.help-chat-send {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 8px;
|
||||
background: var(--accent);
|
||||
color: var(--bg-primary);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
.help-chat-send:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.help-chat-send:not(:disabled):hover {
|
||||
background: var(--accent-hover);
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ pub enum Route {
|
||||
PentestSessionPage { session_id: String },
|
||||
#[route("/mcp-servers")]
|
||||
McpServersPage {},
|
||||
#[route("/settings")]
|
||||
SettingsPage {},
|
||||
}
|
||||
|
sharang
commented
[medium] Missing Settings Page Route The SettingsPage route was removed from the Route enum but there might be existing references or navigation code that still expects this route to exist. This could lead to runtime errors if any navigation attempts to access the settings page. Suggested fix: Verify that all references to the SettingsPage route have been removed from the application codebase. If there are any remaining references, they should be updated or removed to prevent runtime errors. *Scanner: code-review/logic | * **[medium] Missing Settings Page Route**
The SettingsPage route was removed from the Route enum but there might be existing references or navigation code that still expects this route to exist. This could lead to runtime errors if any navigation attempts to access the settings page.
Suggested fix: Verify that all references to the SettingsPage route have been removed from the application codebase. If there are any remaining references, they should be updated or removed to prevent runtime errors.
*Scanner: code-review/logic | *
<!-- compliance-fp:e98f192b02bf8a9873f0c894afedb6ecff82abb693fff8d2bd066803a870e164 -->
sharang
commented
[medium] Missing Settings Page Route The SettingsPage route was removed from the Route enum but there might be existing references or navigation code that still expects this route to exist. This could lead to runtime errors if any navigation attempts to access the settings page. Suggested fix: Verify that all references to the SettingsPage route have been removed from the application codebase. If there are any remaining references, they should be updated or removed to prevent runtime errors. *Scanner: code-review/logic | * **[medium] Missing Settings Page Route**
The SettingsPage route was removed from the Route enum but there might be existing references or navigation code that still expects this route to exist. This could lead to runtime errors if any navigation attempts to access the settings page.
Suggested fix: Verify that all references to the SettingsPage route have been removed from the application codebase. If there are any remaining references, they should be updated or removed to prevent runtime errors.
*Scanner: code-review/logic | *
<!-- compliance-fp:e98f192b02bf8a9873f0c894afedb6ecff82abb693fff8d2bd066803a870e164 -->
|
||||
|
||||
const FAVICON: Asset = asset!("/assets/favicon.svg");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::app::Route;
|
||||
use crate::components::help_chat::HelpChat;
|
||||
use crate::components::sidebar::Sidebar;
|
||||
use crate::components::toast::{ToastContainer, Toasts};
|
||||
use crate::infrastructure::auth_check::check_auth;
|
||||
@@ -21,6 +22,7 @@ pub fn AppShell() -> Element {
|
||||
Outlet::<Route> {}
|
||||
}
|
||||
ToastContainer {}
|
||||
HelpChat {}
|
||||
|
sharang
commented
[medium] Missing error handling for authentication check The Suggested fix: Add proper error handling around the *Scanner: code-review/convention | * **[medium] Missing error handling for authentication check**
The `check_auth` function is called without handling potential errors. If authentication fails, the application should handle this gracefully rather than panicking or silently failing.
Suggested fix: Add proper error handling around the `check_auth()` call, such as using `?` operator or explicit match statement to handle potential authentication failures.
*Scanner: code-review/convention | *
<!-- compliance-fp:de795707203c986bc9f3f4cf6bd83af50bf48af6266eaf35340c04714ca55749 -->
sharang
commented
[high] Missing Input Validation in Help Chat Component The help chat component allows user input without proper sanitization or validation. This could lead to XSS vulnerabilities if chat messages are displayed without proper escaping, or injection attacks if the input is used in backend operations. Suggested fix: Implement proper input validation and sanitization for all user-provided content in the help chat component. Ensure all messages are escaped when rendered and validate input length and content types. Scanner: code-review/security | CWE: CWE-79 **[high] Missing Input Validation in Help Chat Component**
The help chat component allows user input without proper sanitization or validation. This could lead to XSS vulnerabilities if chat messages are displayed without proper escaping, or injection attacks if the input is used in backend operations.
Suggested fix: Implement proper input validation and sanitization for all user-provided content in the help chat component. Ensure all messages are escaped when rendered and validate input length and content types.
*Scanner: code-review/security | CWE: CWE-79*
<!-- compliance-fp:5efe855ddaf6054d207ee40d34ca5f7eebc3be765b7d13f57e305c57e8e95245 -->
sharang
commented
[medium] Missing error handling for authentication check The Suggested fix: Add proper error handling around the *Scanner: code-review/convention | * **[medium] Missing error handling for authentication check**
The `check_auth` function is called without handling potential errors. If authentication fails, the application should handle this gracefully rather than panicking or silently failing.
Suggested fix: Add proper error handling around the `check_auth()` call, such as using `?` operator or explicit match statement to handle potential authentication failures.
*Scanner: code-review/convention | *
<!-- compliance-fp:de795707203c986bc9f3f4cf6bd83af50bf48af6266eaf35340c04714ca55749 -->
sharang
commented
[high] Missing Input Validation in Help Chat Component The help chat component allows user input without proper sanitization or validation. This could lead to XSS vulnerabilities if chat messages are displayed without proper escaping, or injection attacks if the input is used in backend operations. Suggested fix: Implement proper input validation and sanitization for all user-provided content in the help chat component. Ensure all messages are escaped when rendered and validate input length and content types. Scanner: code-review/security | CWE: CWE-79 **[high] Missing Input Validation in Help Chat Component**
The help chat component allows user input without proper sanitization or validation. This could lead to XSS vulnerabilities if chat messages are displayed without proper escaping, or injection attacks if the input is used in backend operations.
Suggested fix: Implement proper input validation and sanitization for all user-provided content in the help chat component. Ensure all messages are escaped when rendered and validate input length and content types.
*Scanner: code-review/security | CWE: CWE-79*
<!-- compliance-fp:5efe855ddaf6054d207ee40d34ca5f7eebc3be765b7d13f57e305c57e8e95245 -->
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
198
compliance-dashboard/src/components/help_chat.rs
Normal file
@@ -0,0 +1,198 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_free_icons::icons::bs_icons::*;
|
||||
use dioxus_free_icons::Icon;
|
||||
|
||||
use crate::infrastructure::help_chat::{send_help_chat_message, HelpChatHistoryMessage};
|
||||
|
||||
// ── Message model ────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ChatMsg {
|
||||
role: String,
|
||||
content: String,
|
||||
}
|
||||
|
||||
// ── Component ────────────────────────────────────────────────────────────────
|
||||
|
||||
#[component]
|
||||
pub fn HelpChat() -> Element {
|
||||
let mut is_open = use_signal(|| false);
|
||||
let mut messages = use_signal(Vec::<ChatMsg>::new);
|
||||
let mut input_text = use_signal(String::new);
|
||||
let mut is_loading = use_signal(|| false);
|
||||
|
||||
// Send message handler
|
||||
let on_send = move |_| {
|
||||
let text = input_text().trim().to_string();
|
||||
if text.is_empty() || is_loading() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
sharang
commented
[medium] Duplicate message sending logic The message sending logic is duplicated between the Suggested fix: Extract the common message sending logic into a separate function to reduce duplication. *Scanner: code-review/logic | * **[medium] Duplicate message sending logic**
The message sending logic is duplicated between the `on_send` handler and the `on_keydown` handler. This increases maintenance burden and potential for inconsistencies.
Suggested fix: Extract the common message sending logic into a separate function to reduce duplication.
*Scanner: code-review/logic | *
<!-- compliance-fp:4a3ad18f1142af771333ce03700b303426d73596856374942e116d0950938806 -->
sharang
commented
[medium] Code Duplication in Message Sending Logic The message sending logic is duplicated in both the on_send handler and on_keydown handler. Both handlers perform identical operations for adding user messages, building history, and calling the API. This duplication increases maintenance burden and risk of inconsistencies. Suggested fix: Extract the common message sending logic into a separate async function or closure that can be reused by both event handlers. This will reduce code duplication and make the component easier to maintain. *Scanner: code-review/complexity | * **[medium] Code Duplication in Message Sending Logic**
The message sending logic is duplicated in both the on_send handler and on_keydown handler. Both handlers perform identical operations for adding user messages, building history, and calling the API. This duplication increases maintenance burden and risk of inconsistencies.
Suggested fix: Extract the common message sending logic into a separate async function or closure that can be reused by both event handlers. This will reduce code duplication and make the component easier to maintain.
*Scanner: code-review/complexity | *
<!-- compliance-fp:8ba6816e031ac4318642b78525a4794cb162878c271453d9aecaca3bac12a7bc -->
sharang
commented
[medium] Duplicate message sending logic The message sending logic is duplicated between the Suggested fix: Extract the common message sending logic into a separate function to reduce duplication. *Scanner: code-review/logic | * **[medium] Duplicate message sending logic**
The message sending logic is duplicated between the `on_send` handler and the `on_keydown` handler. This increases maintenance burden and potential for inconsistencies.
Suggested fix: Extract the common message sending logic into a separate function to reduce duplication.
*Scanner: code-review/logic | *
<!-- compliance-fp:4a3ad18f1142af771333ce03700b303426d73596856374942e116d0950938806 -->
sharang
commented
[medium] Code Duplication in Message Sending Logic The message sending logic is duplicated in both the on_send handler and on_keydown handler. Both handlers perform identical operations for adding user messages, building history, and calling the API. This duplication increases maintenance burden and risk of inconsistencies. Suggested fix: Extract the common message sending logic into a separate async function or closure that can be reused by both event handlers. This will reduce code duplication and make the component easier to maintain. *Scanner: code-review/complexity | * **[medium] Code Duplication in Message Sending Logic**
The message sending logic is duplicated in both the on_send handler and on_keydown handler. Both handlers perform identical operations for adding user messages, building history, and calling the API. This duplication increases maintenance burden and risk of inconsistencies.
Suggested fix: Extract the common message sending logic into a separate async function or closure that can be reused by both event handlers. This will reduce code duplication and make the component easier to maintain.
*Scanner: code-review/complexity | *
<!-- compliance-fp:8ba6816e031ac4318642b78525a4794cb162878c271453d9aecaca3bac12a7bc -->
|
||||
// Push user message
|
||||
messages.write().push(ChatMsg {
|
||||
role: "user".into(),
|
||||
content: text.clone(),
|
||||
});
|
||||
|
sharang
commented
[medium] Potential race condition in loading state management The Suggested fix: Consider using a more sophisticated concurrency control mechanism or ensuring that only one request can be active at a time. *Scanner: code-review/logic | * **[medium] Potential race condition in loading state management**
The `is_loading` flag is set to true before the async operation starts, but there's no mechanism to prevent multiple concurrent requests. If a user rapidly sends messages, multiple requests could be in flight simultaneously.
Suggested fix: Consider using a more sophisticated concurrency control mechanism or ensuring that only one request can be active at a time.
*Scanner: code-review/logic | *
<!-- compliance-fp:d4362199ba134252ca66ab1dd911148ee16de4d55cf45621708f7ca33980c4a7 -->
sharang
commented
[medium] Potential race condition in loading state management The Suggested fix: Consider using a more sophisticated concurrency control mechanism or ensuring that only one request can be active at a time. *Scanner: code-review/logic | * **[medium] Potential race condition in loading state management**
The `is_loading` flag is set to true before the async operation starts, but there's no mechanism to prevent multiple concurrent requests. If a user rapidly sends messages, multiple requests could be in flight simultaneously.
Suggested fix: Consider using a more sophisticated concurrency control mechanism or ensuring that only one request can be active at a time.
*Scanner: code-review/logic | *
<!-- compliance-fp:d4362199ba134252ca66ab1dd911148ee16de4d55cf45621708f7ca33980c4a7 -->
|
||||
input_text.set(String::new());
|
||||
is_loading.set(true);
|
||||
|
||||
// Build history for API call (exclude last user message, it goes as `message`)
|
||||
let history: Vec<HelpChatHistoryMessage> = messages()
|
||||
.iter()
|
||||
.rev()
|
||||
.skip(1) // skip the user message we just added
|
||||
.rev()
|
||||
.map(|m| HelpChatHistoryMessage {
|
||||
|
sharang
commented
[medium] Redundant message history construction The code builds the message history by reversing the vector twice, which is inefficient and unnecessary. The logic should be simplified to avoid redundant operations. Suggested fix: Simplify the history construction by directly collecting from the iterator without double reversal: *Scanner: code-review/logic | * **[medium] Redundant message history construction**
The code builds the message history by reversing the vector twice, which is inefficient and unnecessary. The logic should be simplified to avoid redundant operations.
Suggested fix: Simplify the history construction by directly collecting from the iterator without double reversal: `messages().iter().take(messages().len().saturating_sub(1)).rev().map(...)`
*Scanner: code-review/logic | *
<!-- compliance-fp:b31d1429c8e32048ebb20102715433c34068eb33f4622c17e90b95312950c863 -->
sharang
commented
[medium] Redundant message history construction The code builds the message history by reversing the vector twice, which is inefficient and unnecessary. The logic should be simplified to avoid redundant operations. Suggested fix: Simplify the history construction by directly collecting from the iterator without double reversal: *Scanner: code-review/logic | * **[medium] Redundant message history construction**
The code builds the message history by reversing the vector twice, which is inefficient and unnecessary. The logic should be simplified to avoid redundant operations.
Suggested fix: Simplify the history construction by directly collecting from the iterator without double reversal: `messages().iter().take(messages().len().saturating_sub(1)).rev().map(...)`
*Scanner: code-review/logic | *
<!-- compliance-fp:b31d1429c8e32048ebb20102715433c34068eb33f4622c17e90b95312950c863 -->
|
||||
role: m.role.clone(),
|
||||
content: m.content.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
spawn(async move {
|
||||
match send_help_chat_message(text, history).await {
|
||||
Ok(resp) => {
|
||||
|
sharang
commented
[medium] Inconsistent error handling in async blocks The error handling pattern in the async blocks differs between the Suggested fix: Extract the common async message sending logic into a separate function or closure to avoid duplication and ensure consistent error handling. *Scanner: code-review/convention | * **[medium] Inconsistent error handling in async blocks**
The error handling pattern in the async blocks differs between the `on_send` and `on_keydown` handlers. The `on_keydown` handler duplicates the entire message sending logic including the loading state management, while `on_send` uses a more concise approach. This inconsistency makes the code harder to maintain and increases the risk of divergence.
Suggested fix: Extract the common async message sending logic into a separate function or closure to avoid duplication and ensure consistent error handling.
*Scanner: code-review/convention | *
<!-- compliance-fp:8ba195efc69ebe6441439d066945a7fd8de1970993a665125905f0b96132a9e2 -->
sharang
commented
[medium] Inconsistent error handling in async blocks The error handling pattern in the async blocks differs between the Suggested fix: Extract the common async message sending logic into a separate function or closure to avoid duplication and ensure consistent error handling. *Scanner: code-review/convention | * **[medium] Inconsistent error handling in async blocks**
The error handling pattern in the async blocks differs between the `on_send` and `on_keydown` handlers. The `on_keydown` handler duplicates the entire message sending logic including the loading state management, while `on_send` uses a more concise approach. This inconsistency makes the code harder to maintain and increases the risk of divergence.
Suggested fix: Extract the common async message sending logic into a separate function or closure to avoid duplication and ensure consistent error handling.
*Scanner: code-review/convention | *
<!-- compliance-fp:8ba195efc69ebe6441439d066945a7fd8de1970993a665125905f0b96132a9e2 -->
|
||||
messages.write().push(ChatMsg {
|
||||
role: "assistant".into(),
|
||||
content: resp.data.message,
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
messages.write().push(ChatMsg {
|
||||
role: "assistant".into(),
|
||||
content: format!("Error: {e}"),
|
||||
});
|
||||
|
sharang
commented
[medium] Complex Boolean Expression in Key Handler The key handler contains a complex boolean expression checking for Enter key press and shift modifier state. The condition 'if e.key() == Key::Enter && !e.modifiers().shift()' is hard to read and understand at a glance, especially when combined with the subsequent empty/loading checks. Suggested fix: Break down the complex boolean expression into clear, named variables or extract the key handling logic into a separate function with descriptive names to improve readability. *Scanner: code-review/complexity | * **[medium] Complex Boolean Expression in Key Handler**
The key handler contains a complex boolean expression checking for Enter key press and shift modifier state. The condition 'if e.key() == Key::Enter && !e.modifiers().shift()' is hard to read and understand at a glance, especially when combined with the subsequent empty/loading checks.
Suggested fix: Break down the complex boolean expression into clear, named variables or extract the key handling logic into a separate function with descriptive names to improve readability.
*Scanner: code-review/complexity | *
<!-- compliance-fp:c8e1e69a1b973a9e7f8a5ba5c9603467e4870efc167e256b955a68fa867176c1 -->
sharang
commented
[medium] Complex Boolean Expression in Key Handler The key handler contains a complex boolean expression checking for Enter key press and shift modifier state. The condition 'if e.key() == Key::Enter && !e.modifiers().shift()' is hard to read and understand at a glance, especially when combined with the subsequent empty/loading checks. Suggested fix: Break down the complex boolean expression into clear, named variables or extract the key handling logic into a separate function with descriptive names to improve readability. *Scanner: code-review/complexity | * **[medium] Complex Boolean Expression in Key Handler**
The key handler contains a complex boolean expression checking for Enter key press and shift modifier state. The condition 'if e.key() == Key::Enter && !e.modifiers().shift()' is hard to read and understand at a glance, especially when combined with the subsequent empty/loading checks.
Suggested fix: Break down the complex boolean expression into clear, named variables or extract the key handling logic into a separate function with descriptive names to improve readability.
*Scanner: code-review/complexity | *
<!-- compliance-fp:c8e1e69a1b973a9e7f8a5ba5c9603467e4870efc167e256b955a68fa867176c1 -->
|
||||
}
|
||||
}
|
||||
is_loading.set(false);
|
||||
});
|
||||
|
sharang
commented
[low] Redundant string conversion in message building The code converts strings to owned values unnecessarily when building the history vector. Specifically, Suggested fix: Remove the *Scanner: code-review/convention | * **[low] Redundant string conversion in message building**
The code converts strings to owned values unnecessarily when building the history vector. Specifically, `m.role.clone()` and `m.content.clone()` are called even though these are already owned strings. This creates unnecessary allocations.
Suggested fix: Remove the `.clone()` calls since `role` and `content` are already `String` types and don't need cloning.
*Scanner: code-review/convention | *
<!-- compliance-fp:f82a85323b8d93e39c8bc2f72b8027db9fbac0cf933bf94d9615533344d0b98c -->
sharang
commented
[low] Redundant string conversion in message building The code converts strings to owned values unnecessarily when building the history vector. Specifically, Suggested fix: Remove the *Scanner: code-review/convention | * **[low] Redundant string conversion in message building**
The code converts strings to owned values unnecessarily when building the history vector. Specifically, `m.role.clone()` and `m.content.clone()` are called even though these are already owned strings. This creates unnecessary allocations.
Suggested fix: Remove the `.clone()` calls since `role` and `content` are already `String` types and don't need cloning.
*Scanner: code-review/convention | *
<!-- compliance-fp:f82a85323b8d93e39c8bc2f72b8027db9fbac0cf933bf94d9615533344d0b98c -->
|
||||
};
|
||||
|
||||
// Key handler for Enter to send
|
||||
let on_keydown = move |e: KeyboardEvent| {
|
||||
if e.key() == Key::Enter && !e.modifiers().shift() {
|
||||
e.prevent_default();
|
||||
let text = input_text().trim().to_string();
|
||||
if text.is_empty() || is_loading() {
|
||||
return;
|
||||
}
|
||||
messages.write().push(ChatMsg {
|
||||
role: "user".into(),
|
||||
content: text.clone(),
|
||||
});
|
||||
input_text.set(String::new());
|
||||
is_loading.set(true);
|
||||
|
||||
let history: Vec<HelpChatHistoryMessage> = messages()
|
||||
.iter()
|
||||
.rev()
|
||||
.skip(1)
|
||||
.rev()
|
||||
.map(|m| HelpChatHistoryMessage {
|
||||
role: m.role.clone(),
|
||||
content: m.content.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
spawn(async move {
|
||||
match send_help_chat_message(text, history).await {
|
||||
Ok(resp) => {
|
||||
messages.write().push(ChatMsg {
|
||||
role: "assistant".into(),
|
||||
content: resp.data.message,
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
messages.write().push(ChatMsg {
|
||||
role: "assistant".into(),
|
||||
content: format!("Error: {e}"),
|
||||
});
|
||||
}
|
||||
}
|
||||
is_loading.set(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
rsx! {
|
||||
// Floating toggle button
|
||||
if !is_open() {
|
||||
button {
|
||||
class: "help-chat-toggle",
|
||||
|
sharang
commented
[medium] Deeply Nested Control Flow The component has deeply nested control flow with multiple conditional blocks (if statements) inside the main render tree. The message rendering section contains nested conditions for empty state, message iteration, and loading state, making the structure harder to follow. Suggested fix: Consider extracting the message rendering logic into separate components or functions to flatten the nesting and improve readability. The complex conditional rendering could be simplified by breaking it into smaller, more focused pieces. *Scanner: code-review/complexity | * **[medium] Deeply Nested Control Flow**
The component has deeply nested control flow with multiple conditional blocks (if statements) inside the main render tree. The message rendering section contains nested conditions for empty state, message iteration, and loading state, making the structure harder to follow.
Suggested fix: Consider extracting the message rendering logic into separate components or functions to flatten the nesting and improve readability. The complex conditional rendering could be simplified by breaking it into smaller, more focused pieces.
*Scanner: code-review/complexity | *
<!-- compliance-fp:7f896e41acb42f08181ca6a6d5ddbfbd948c9f490e4466e1b8c773ce1a412038 -->
sharang
commented
[medium] Deeply Nested Control Flow The component has deeply nested control flow with multiple conditional blocks (if statements) inside the main render tree. The message rendering section contains nested conditions for empty state, message iteration, and loading state, making the structure harder to follow. Suggested fix: Consider extracting the message rendering logic into separate components or functions to flatten the nesting and improve readability. The complex conditional rendering could be simplified by breaking it into smaller, more focused pieces. *Scanner: code-review/complexity | * **[medium] Deeply Nested Control Flow**
The component has deeply nested control flow with multiple conditional blocks (if statements) inside the main render tree. The message rendering section contains nested conditions for empty state, message iteration, and loading state, making the structure harder to follow.
Suggested fix: Consider extracting the message rendering logic into separate components or functions to flatten the nesting and improve readability. The complex conditional rendering could be simplified by breaking it into smaller, more focused pieces.
*Scanner: code-review/complexity | *
<!-- compliance-fp:7f896e41acb42f08181ca6a6d5ddbfbd948c9f490e4466e1b8c773ce1a412038 -->
|
||||
onclick: move |_| is_open.set(true),
|
||||
title: "Help",
|
||||
Icon { icon: BsQuestionCircle, width: 22, height: 22 }
|
||||
}
|
||||
}
|
||||
|
||||
// Chat panel
|
||||
if is_open() {
|
||||
div { class: "help-chat-panel",
|
||||
// Header
|
||||
div { class: "help-chat-header",
|
||||
span { class: "help-chat-title",
|
||||
Icon { icon: BsRobot, width: 16, height: 16 }
|
||||
"Help Assistant"
|
||||
}
|
||||
button {
|
||||
class: "help-chat-close",
|
||||
onclick: move |_| is_open.set(false),
|
||||
Icon { icon: BsX, width: 18, height: 18 }
|
||||
}
|
||||
}
|
||||
|
||||
|
sharang
commented
[medium] Potential security vulnerability in HTML rendering The component directly uses Suggested fix: Use a proper HTML sanitization library or implement basic sanitization before using *Scanner: code-review/convention | * **[medium] Potential security vulnerability in HTML rendering**
The component directly uses `dangerous_inner_html` for rendering assistant messages without sanitizing the content. This could lead to XSS vulnerabilities if the AI responses contain malicious HTML. Even though this is a controlled environment, it's better to sanitize the HTML before rendering.
Suggested fix: Use a proper HTML sanitization library or implement basic sanitization before using `dangerous_inner_html` to prevent XSS attacks.
*Scanner: code-review/convention | *
<!-- compliance-fp:719753506f037ef6dff0f869ccf146badb2a391e3f59c1a96f57115c1ea4d3f0 -->
sharang
commented
[medium] Potential security vulnerability in HTML rendering The component directly uses Suggested fix: Use a proper HTML sanitization library or implement basic sanitization before using *Scanner: code-review/convention | * **[medium] Potential security vulnerability in HTML rendering**
The component directly uses `dangerous_inner_html` for rendering assistant messages without sanitizing the content. This could lead to XSS vulnerabilities if the AI responses contain malicious HTML. Even though this is a controlled environment, it's better to sanitize the HTML before rendering.
Suggested fix: Use a proper HTML sanitization library or implement basic sanitization before using `dangerous_inner_html` to prevent XSS attacks.
*Scanner: code-review/convention | *
<!-- compliance-fp:719753506f037ef6dff0f869ccf146badb2a391e3f59c1a96f57115c1ea4d3f0 -->
|
||||
// Messages area
|
||||
div { class: "help-chat-messages",
|
||||
if messages().is_empty() {
|
||||
div { class: "help-chat-empty",
|
||||
p { "Ask me anything about the Compliance Scanner." }
|
||||
p { class: "help-chat-hint",
|
||||
"e.g. \"How do I add a repository?\" or \"What is SBOM?\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
sharang
commented
[high] Inefficient HTML sanitization approach The basic string replacement approach for markdown rendering is fragile and doesn't handle nested tags properly. It could lead to XSS vulnerabilities or malformed HTML. Suggested fix: Use a proper markdown parser library instead of manual string replacements for safer and more accurate rendering. *Scanner: code-review/logic | * **[high] Inefficient HTML sanitization approach**
The basic string replacement approach for markdown rendering is fragile and doesn't handle nested tags properly. It could lead to XSS vulnerabilities or malformed HTML.
Suggested fix: Use a proper markdown parser library instead of manual string replacements for safer and more accurate rendering.
*Scanner: code-review/logic | *
<!-- compliance-fp:57351b0ba07f43970767b11bf2c4265e9c3f4e8f2f9701488c8ea6f2461d94b1 -->
sharang
commented
[high] Inefficient HTML sanitization approach The basic string replacement approach for markdown rendering is fragile and doesn't handle nested tags properly. It could lead to XSS vulnerabilities or malformed HTML. Suggested fix: Use a proper markdown parser library instead of manual string replacements for safer and more accurate rendering. *Scanner: code-review/logic | * **[high] Inefficient HTML sanitization approach**
The basic string replacement approach for markdown rendering is fragile and doesn't handle nested tags properly. It could lead to XSS vulnerabilities or malformed HTML.
Suggested fix: Use a proper markdown parser library instead of manual string replacements for safer and more accurate rendering.
*Scanner: code-review/logic | *
<!-- compliance-fp:57351b0ba07f43970767b11bf2c4265e9c3f4e8f2f9701488c8ea6f2461d94b1 -->
|
||||
for (i, msg) in messages().iter().enumerate() {
|
||||
|
sharang
commented
[high] Potential XSS Vulnerability via Dangerous Inner HTML The chat component uses Suggested fix: Implement proper HTML sanitization of AI-generated content before rendering it with dangerous_inner_html. Consider using a dedicated HTML sanitizer library or escape all HTML characters in the content before insertion. Scanner: code-review/security | CWE: CWE-79 **[high] Potential XSS Vulnerability via Dangerous Inner HTML**
The chat component uses `dangerous_inner_html` to render assistant messages, which can lead to XSS vulnerabilities if the AI-generated content contains malicious HTML or JavaScript. The content is not properly sanitized before being inserted into the DOM.
Suggested fix: Implement proper HTML sanitization of AI-generated content before rendering it with dangerous_inner_html. Consider using a dedicated HTML sanitizer library or escape all HTML characters in the content before insertion.
*Scanner: code-review/security | CWE: CWE-79*
<!-- compliance-fp:d0427e2a895f180f6dc36236d9f099ae9ba9ccffd867a178590fe3bd47e094ab -->
sharang
commented
[high] Insecure Markdown Rendering Implementation The markdown rendering implementation is basic and vulnerable to XSS attacks. It replaces simple markdown syntax like '**' with HTML tags without proper escaping or sanitization, allowing potential injection of malicious HTML/JS code. Suggested fix: Replace the manual markdown replacement with a secure markdown parser that properly escapes HTML content, or implement comprehensive input sanitization before any HTML manipulation. Scanner: code-review/security | CWE: CWE-79 **[high] Insecure Markdown Rendering Implementation**
The markdown rendering implementation is basic and vulnerable to XSS attacks. It replaces simple markdown syntax like '**' with HTML tags without proper escaping or sanitization, allowing potential injection of malicious HTML/JS code.
Suggested fix: Replace the manual markdown replacement with a secure markdown parser that properly escapes HTML content, or implement comprehensive input sanitization before any HTML manipulation.
*Scanner: code-review/security | CWE: CWE-79*
<!-- compliance-fp:90b39c4404ebec277930bcc05083cb1c14d8761da3f94c92e55b48f696a5e70b -->
sharang
commented
[high] Potential XSS Vulnerability via Dangerous Inner HTML The chat component uses Suggested fix: Implement proper HTML sanitization of AI-generated content before rendering it with dangerous_inner_html. Consider using a dedicated HTML sanitizer library or escape all HTML characters in the content before insertion. Scanner: code-review/security | CWE: CWE-79 **[high] Potential XSS Vulnerability via Dangerous Inner HTML**
The chat component uses `dangerous_inner_html` to render assistant messages, which can lead to XSS vulnerabilities if the AI-generated content contains malicious HTML or JavaScript. The content is not properly sanitized before being inserted into the DOM.
Suggested fix: Implement proper HTML sanitization of AI-generated content before rendering it with dangerous_inner_html. Consider using a dedicated HTML sanitizer library or escape all HTML characters in the content before insertion.
*Scanner: code-review/security | CWE: CWE-79*
<!-- compliance-fp:d0427e2a895f180f6dc36236d9f099ae9ba9ccffd867a178590fe3bd47e094ab -->
sharang
commented
[high] Insecure Markdown Rendering Implementation The markdown rendering implementation is basic and vulnerable to XSS attacks. It replaces simple markdown syntax like '**' with HTML tags without proper escaping or sanitization, allowing potential injection of malicious HTML/JS code. Suggested fix: Replace the manual markdown replacement with a secure markdown parser that properly escapes HTML content, or implement comprehensive input sanitization before any HTML manipulation. Scanner: code-review/security | CWE: CWE-79 **[high] Insecure Markdown Rendering Implementation**
The markdown rendering implementation is basic and vulnerable to XSS attacks. It replaces simple markdown syntax like '**' with HTML tags without proper escaping or sanitization, allowing potential injection of malicious HTML/JS code.
Suggested fix: Replace the manual markdown replacement with a secure markdown parser that properly escapes HTML content, or implement comprehensive input sanitization before any HTML manipulation.
*Scanner: code-review/security | CWE: CWE-79*
<!-- compliance-fp:90b39c4404ebec277930bcc05083cb1c14d8761da3f94c92e55b48f696a5e70b -->
|
||||
div {
|
||||
key: "{i}",
|
||||
class: if msg.role == "user" { "help-msg help-msg-user" } else { "help-msg help-msg-assistant" },
|
||||
div { class: "help-msg-content",
|
||||
dangerous_inner_html: if msg.role == "assistant" {
|
||||
// Basic markdown rendering: bold, code, newlines
|
||||
msg.content
|
||||
.replace("**", "<strong>")
|
||||
.replace("\n\n", "<br><br>")
|
||||
.replace("\n- ", "<br>- ")
|
||||
.replace("`", "<code>")
|
||||
} else {
|
||||
msg.content.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_loading() {
|
||||
div { class: "help-msg help-msg-assistant",
|
||||
div { class: "help-msg-loading", "Thinking..." }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Input area
|
||||
div { class: "help-chat-input",
|
||||
input {
|
||||
r#type: "text",
|
||||
placeholder: "Ask a question...",
|
||||
value: "{input_text}",
|
||||
disabled: is_loading(),
|
||||
oninput: move |e| input_text.set(e.value()),
|
||||
onkeydown: on_keydown,
|
||||
}
|
||||
button {
|
||||
class: "help-chat-send",
|
||||
disabled: is_loading() || input_text().trim().is_empty(),
|
||||
onclick: on_send,
|
||||
Icon { icon: BsSend, width: 14, height: 14 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ pub mod attack_chain;
|
||||
pub mod code_inspector;
|
||||
pub mod code_snippet;
|
||||
pub mod file_tree;
|
||||
pub mod help_chat;
|
||||
pub mod page_header;
|
||||
pub mod pagination;
|
||||
pub mod pentest_wizard;
|
||||
|
||||
@@ -52,11 +52,6 @@ pub fn Sidebar() -> Element {
|
||||
route: Route::PentestDashboardPage {},
|
||||
icon: rsx! { Icon { icon: BsLightningCharge, width: 18, height: 18 } },
|
||||
},
|
||||
NavItem {
|
||||
label: "Settings",
|
||||
route: Route::SettingsPage {},
|
||||
icon: rsx! { Icon { icon: BsGear, width: 18, height: 18 } },
|
||||
},
|
||||
];
|
||||
|
||||
let docs_url = option_env!("DOCS_URL").unwrap_or("/docs");
|
||||
|
||||
59
compliance-dashboard/src/infrastructure/help_chat.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use dioxus::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// ── Response types ──
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct HelpChatApiResponse {
|
||||
pub data: HelpChatResponseData,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct HelpChatResponseData {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
// ── History message type ──
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct HelpChatHistoryMessage {
|
||||
pub role: String,
|
||||
|
sharang
commented
[low] Missing type annotations in server function parameters The Suggested fix: Add explicit type annotations to the function parameters: *Scanner: code-review/convention | * **[low] Missing type annotations in server function parameters**
The `send_help_chat_message` server function parameters lack explicit type annotations, which can make the function signature less clear and harder to maintain. While Rust's type inference works here, explicit annotations improve readability and prevent potential issues during refactoring.
Suggested fix: Add explicit type annotations to the function parameters: `message: String, history: Vec<HelpChatHistoryMessage>`
*Scanner: code-review/convention | *
<!-- compliance-fp:c61ee843fa0277faab515b5c158b6a5d2951b0d8d09cba6deb440b49d2e232fe -->
sharang
commented
[low] Missing type annotations in server function parameters The Suggested fix: Add explicit type annotations to the function parameters: *Scanner: code-review/convention | * **[low] Missing type annotations in server function parameters**
The `send_help_chat_message` server function parameters lack explicit type annotations, which can make the function signature less clear and harder to maintain. While Rust's type inference works here, explicit annotations improve readability and prevent potential issues during refactoring.
Suggested fix: Add explicit type annotations to the function parameters: `message: String, history: Vec<HelpChatHistoryMessage>`
*Scanner: code-review/convention | *
<!-- compliance-fp:c61ee843fa0277faab515b5c158b6a5d2951b0d8d09cba6deb440b49d2e232fe -->
|
||||
pub content: String,
|
||||
}
|
||||
|
sharang
commented
[medium] Insecure Deserialization in Help Chat History Messages The Suggested fix: Add validation checks for the Scanner: code-review/security | CWE: CWE-502 **[medium] Insecure Deserialization in Help Chat History Messages**
The `HelpChatHistoryMessage` struct is used directly in server functions without any validation or sanitization of the `role` and `content` fields. This could lead to unsafe deserialization if these values are not properly validated before being processed or stored.
Suggested fix: Add validation checks for the `role` field to ensure it only accepts expected values (e.g., 'user', 'assistant') and sanitize the `content` field to prevent potential injection attacks.
*Scanner: code-review/security | CWE: CWE-502*
<!-- compliance-fp:5dd2470742b160c92445fceb9fb5d62c270d3bfbff1ec4b0cfc0cab824409aa4 -->
sharang
commented
[medium] Insecure Deserialization in Help Chat History Messages The Suggested fix: Add validation checks for the Scanner: code-review/security | CWE: CWE-502 **[medium] Insecure Deserialization in Help Chat History Messages**
The `HelpChatHistoryMessage` struct is used directly in server functions without any validation or sanitization of the `role` and `content` fields. This could lead to unsafe deserialization if these values are not properly validated before being processed or stored.
Suggested fix: Add validation checks for the `role` field to ensure it only accepts expected values (e.g., 'user', 'assistant') and sanitize the `content` field to prevent potential injection attacks.
*Scanner: code-review/security | CWE: CWE-502*
<!-- compliance-fp:5dd2470742b160c92445fceb9fb5d62c270d3bfbff1ec4b0cfc0cab824409aa4 -->
|
||||
|
||||
// ── Server function ──
|
||||
|
||||
|
sharang
commented
[high] Potential Server-Side Request Forgery (SSRF) via Help Chat API The Suggested fix: Validate and sanitize Scanner: code-review/security | CWE: CWE-918 **[high] Potential Server-Side Request Forgery (SSRF) via Help Chat API**
The `send_help_chat_message` function constructs a URL using `state.agent_api_url` which is likely configurable. If this value is controlled by user input or improperly validated, it could allow an attacker to make requests to internal services that should not be accessible from outside the application.
Suggested fix: Validate and sanitize `state.agent_api_url` to ensure it points to trusted domains only. Implement strict domain whitelisting or use a predefined list of allowed URLs.
*Scanner: code-review/security | CWE: CWE-918*
<!-- compliance-fp:84b9f9b14d5077578fff0240ff66b329f1739d487489e0e55a2d0effc0b56f7b -->
sharang
commented
[high] Potential Server-Side Request Forgery (SSRF) via Help Chat API The Suggested fix: Validate and sanitize Scanner: code-review/security | CWE: CWE-918 **[high] Potential Server-Side Request Forgery (SSRF) via Help Chat API**
The `send_help_chat_message` function constructs a URL using `state.agent_api_url` which is likely configurable. If this value is controlled by user input or improperly validated, it could allow an attacker to make requests to internal services that should not be accessible from outside the application.
Suggested fix: Validate and sanitize `state.agent_api_url` to ensure it points to trusted domains only. Implement strict domain whitelisting or use a predefined list of allowed URLs.
*Scanner: code-review/security | CWE: CWE-918*
<!-- compliance-fp:84b9f9b14d5077578fff0240ff66b329f1739d487489e0e55a2d0effc0b56f7b -->
|
||||
#[server]
|
||||
|
sharang
commented
[medium] Inconsistent error handling in server function The Suggested fix: Consider using more specific error types or consistent error wrapping patterns throughout the server function to maintain uniform error handling across the application. *Scanner: code-review/convention | * **[medium] Inconsistent error handling in server function**
The `send_help_chat_message` function uses `ServerFnError::new()` for all error cases, but the pattern of wrapping errors with `format!()` and `to_string()` is inconsistent with typical server function error handling patterns where more structured error handling might be preferred.
Suggested fix: Consider using more specific error types or consistent error wrapping patterns throughout the server function to maintain uniform error handling across the application.
*Scanner: code-review/convention | *
<!-- compliance-fp:c13f9ee9918b635071d49eb0b94ac4a9a07f9b4339944710fd4eab4af7212062 -->
sharang
commented
[medium] Inconsistent error handling in server function The Suggested fix: Consider using more specific error types or consistent error wrapping patterns throughout the server function to maintain uniform error handling across the application. *Scanner: code-review/convention | * **[medium] Inconsistent error handling in server function**
The `send_help_chat_message` function uses `ServerFnError::new()` for all error cases, but the pattern of wrapping errors with `format!()` and `to_string()` is inconsistent with typical server function error handling patterns where more structured error handling might be preferred.
Suggested fix: Consider using more specific error types or consistent error wrapping patterns throughout the server function to maintain uniform error handling across the application.
*Scanner: code-review/convention | *
<!-- compliance-fp:c13f9ee9918b635071d49eb0b94ac4a9a07f9b4339944710fd4eab4af7212062 -->
|
||||
pub async fn send_help_chat_message(
|
||||
message: String,
|
||||
history: Vec<HelpChatHistoryMessage>,
|
||||
) -> Result<HelpChatApiResponse, ServerFnError> {
|
||||
|
sharang
commented
[medium] Complex boolean expression in server function The Suggested fix: Extract the error handling logic into separate helper functions or use a more concise error handling pattern like the *Scanner: code-review/complexity | * **[medium] Complex boolean expression in server function**
The `send_help_chat_message` function contains a complex chain of `.map_err()` calls that make error handling hard to follow and reason about. Each step adds another layer of error conversion which reduces readability.
Suggested fix: Extract the error handling logic into separate helper functions or use a more concise error handling pattern like the `?` operator with custom error types to reduce nesting and improve readability.
*Scanner: code-review/complexity | *
<!-- compliance-fp:1fbd0057afae2589da01a39b6bad27ec8d642d8830ff6e9061b5df9af19c3d43 -->
sharang
commented
[medium] Complex boolean expression in server function The Suggested fix: Extract the error handling logic into separate helper functions or use a more concise error handling pattern like the *Scanner: code-review/complexity | * **[medium] Complex boolean expression in server function**
The `send_help_chat_message` function contains a complex chain of `.map_err()` calls that make error handling hard to follow and reason about. Each step adds another layer of error conversion which reduces readability.
Suggested fix: Extract the error handling logic into separate helper functions or use a more concise error handling pattern like the `?` operator with custom error types to reduce nesting and improve readability.
*Scanner: code-review/complexity | *
<!-- compliance-fp:1fbd0057afae2589da01a39b6bad27ec8d642d8830ff6e9061b5df9af19c3d43 -->
|
||||
let state: super::server_state::ServerState =
|
||||
dioxus_fullstack::FullstackContext::extract().await?;
|
||||
|
||||
let url = format!("{}/api/v1/help/chat", state.agent_api_url);
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(120))
|
||||
.build()
|
||||
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
||||
|
||||
let resp = client
|
||||
.post(&url)
|
||||
.json(&serde_json::json!({
|
||||
"message": message,
|
||||
"history": history,
|
||||
|
sharang
commented
[high] Missing error handling for HTTP response status The Suggested fix: Add a check for successful HTTP status codes before attempting to read and parse the response body. For example: *Scanner: code-review/logic | * **[high] Missing error handling for HTTP response status**
The `send_help_chat_message` function sends an HTTP POST request but doesn't check the response status code. If the server returns an error status (like 4xx or 5xx), the function will still try to parse the response as successful, potentially leading to incorrect behavior or crashes.
Suggested fix: Add a check for successful HTTP status codes before attempting to read and parse the response body. For example: `resp.status().is_success().then_some(()).ok_or_else(|| ServerFnError::new("HTTP request failed"))?;`
*Scanner: code-review/logic | *
<!-- compliance-fp:bc21aa8f66f791ad32898d0c4a9b2716347a12b72c90312c9121bc0eda82a660 -->
sharang
commented
[high] Missing error handling for HTTP response status The Suggested fix: Add a check for successful HTTP status codes before attempting to read and parse the response body. For example: *Scanner: code-review/logic | * **[high] Missing error handling for HTTP response status**
The `send_help_chat_message` function sends an HTTP POST request but doesn't check the response status code. If the server returns an error status (like 4xx or 5xx), the function will still try to parse the response as successful, potentially leading to incorrect behavior or crashes.
Suggested fix: Add a check for successful HTTP status codes before attempting to read and parse the response body. For example: `resp.status().is_success().then_some(()).ok_or_else(|| ServerFnError::new("HTTP request failed"))?;`
*Scanner: code-review/logic | *
<!-- compliance-fp:bc21aa8f66f791ad32898d0c4a9b2716347a12b72c90312c9121bc0eda82a660 -->
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| ServerFnError::new(format!("Help chat request failed: {e}")))?;
|
||||
|
||||
let text = resp
|
||||
.text()
|
||||
.await
|
||||
.map_err(|e| ServerFnError::new(format!("Failed to read response: {e}")))?;
|
||||
|
||||
let body: HelpChatApiResponse = serde_json::from_str(&text)
|
||||
.map_err(|e| ServerFnError::new(format!("Failed to parse response: {e}")))?;
|
||||
|
||||
Ok(body)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ pub mod chat;
|
||||
pub mod dast;
|
||||
pub mod findings;
|
||||
pub mod graph;
|
||||
pub mod help_chat;
|
||||
pub mod issues;
|
||||
pub mod mcp;
|
||||
pub mod pentest;
|
||||
|
||||
@@ -16,7 +16,6 @@ pub mod pentest_dashboard;
|
||||
pub mod pentest_session;
|
||||
pub mod repositories;
|
||||
pub mod sbom;
|
||||
pub mod settings;
|
||||
|
||||
pub use chat::ChatPage;
|
||||
pub use chat_index::ChatIndexPage;
|
||||
@@ -36,4 +35,3 @@ pub use pentest_dashboard::PentestDashboardPage;
|
||||
pub use pentest_session::PentestSessionPage;
|
||||
pub use repositories::RepositoriesPage;
|
||||
pub use sbom::SbomPage;
|
||||
pub use settings::SettingsPage;
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::components::page_header::PageHeader;
|
||||
|
||||
#[component]
|
||||
pub fn SettingsPage() -> Element {
|
||||
let mut litellm_url = use_signal(|| "http://localhost:4000".to_string());
|
||||
let mut litellm_model = use_signal(|| "gpt-4o".to_string());
|
||||
let mut github_token = use_signal(String::new);
|
||||
let mut gitlab_url = use_signal(|| "https://gitlab.com".to_string());
|
||||
let mut gitlab_token = use_signal(String::new);
|
||||
let mut jira_url = use_signal(String::new);
|
||||
let mut jira_email = use_signal(String::new);
|
||||
let mut jira_token = use_signal(String::new);
|
||||
let mut jira_project = use_signal(String::new);
|
||||
let mut searxng_url = use_signal(|| "http://localhost:8888".to_string());
|
||||
|
||||
rsx! {
|
||||
PageHeader {
|
||||
title: "Settings",
|
||||
description: "Configure integrations and scanning parameters",
|
||||
}
|
||||
|
||||
div { class: "card",
|
||||
div { class: "card-header", "LiteLLM Configuration" }
|
||||
div { class: "form-group",
|
||||
label { "LiteLLM URL" }
|
||||
input {
|
||||
r#type: "text",
|
||||
value: "{litellm_url}",
|
||||
oninput: move |e| litellm_url.set(e.value()),
|
||||
}
|
||||
}
|
||||
div { class: "form-group",
|
||||
label { "Model" }
|
||||
input {
|
||||
r#type: "text",
|
||||
value: "{litellm_model}",
|
||||
oninput: move |e| litellm_model.set(e.value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div { class: "card",
|
||||
div { class: "card-header", "GitHub Integration" }
|
||||
div { class: "form-group",
|
||||
label { "Personal Access Token" }
|
||||
input {
|
||||
r#type: "password",
|
||||
placeholder: "ghp_...",
|
||||
value: "{github_token}",
|
||||
oninput: move |e| github_token.set(e.value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div { class: "card",
|
||||
div { class: "card-header", "GitLab Integration" }
|
||||
div { class: "form-group",
|
||||
label { "GitLab URL" }
|
||||
input {
|
||||
r#type: "text",
|
||||
value: "{gitlab_url}",
|
||||
oninput: move |e| gitlab_url.set(e.value()),
|
||||
}
|
||||
}
|
||||
div { class: "form-group",
|
||||
label { "Access Token" }
|
||||
input {
|
||||
r#type: "password",
|
||||
placeholder: "glpat-...",
|
||||
value: "{gitlab_token}",
|
||||
oninput: move |e| gitlab_token.set(e.value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div { class: "card",
|
||||
div { class: "card-header", "Jira Integration" }
|
||||
div { class: "form-group",
|
||||
label { "Jira URL" }
|
||||
input {
|
||||
r#type: "text",
|
||||
placeholder: "https://your-org.atlassian.net",
|
||||
value: "{jira_url}",
|
||||
oninput: move |e| jira_url.set(e.value()),
|
||||
}
|
||||
}
|
||||
div { class: "form-group",
|
||||
label { "Email" }
|
||||
input {
|
||||
r#type: "email",
|
||||
value: "{jira_email}",
|
||||
oninput: move |e| jira_email.set(e.value()),
|
||||
}
|
||||
}
|
||||
div { class: "form-group",
|
||||
label { "API Token" }
|
||||
input {
|
||||
r#type: "password",
|
||||
value: "{jira_token}",
|
||||
oninput: move |e| jira_token.set(e.value()),
|
||||
}
|
||||
}
|
||||
div { class: "form-group",
|
||||
label { "Project Key" }
|
||||
input {
|
||||
r#type: "text",
|
||||
placeholder: "SEC",
|
||||
value: "{jira_project}",
|
||||
oninput: move |e| jira_project.set(e.value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div { class: "card",
|
||||
div { class: "card-header", "SearXNG" }
|
||||
div { class: "form-group",
|
||||
label { "SearXNG URL" }
|
||||
input {
|
||||
r#type: "text",
|
||||
value: "{searxng_url}",
|
||||
oninput: move |e| searxng_url.set(e.value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div { style: "margin-top: 16px;",
|
||||
button {
|
||||
class: "btn btn-primary",
|
||||
onclick: move |_| {
|
||||
tracing::info!("Settings save not yet implemented - settings are managed via .env");
|
||||
},
|
||||
"Save Settings"
|
||||
}
|
||||
p {
|
||||
style: "margin-top: 8px; font-size: 12px; color: var(--text-secondary);",
|
||||
"Note: Settings are currently configured via environment variables (.env file). Dashboard-based settings persistence coming soon."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
61
docs/features/deduplication.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Finding Deduplication
|
||||
|
sharang
commented
[low] Inconsistent error handling pattern in documentation The documentation files don't show any error handling patterns, but this is a documentation change rather than code. However, since this appears to be part of a codebase that might include code examples or API documentation, the absence of error handling considerations in these markdown files could indicate a maintenance issue if they're meant to document actual implementation details. Suggested fix: Consider adding a note about error handling in deduplication logic if this documentation is meant to describe implementation details *Scanner: code-review/convention | * **[low] Inconsistent error handling pattern in documentation**
The documentation files don't show any error handling patterns, but this is a documentation change rather than code. However, since this appears to be part of a codebase that might include code examples or API documentation, the absence of error handling considerations in these markdown files could indicate a maintenance issue if they're meant to document actual implementation details.
Suggested fix: Consider adding a note about error handling in deduplication logic if this documentation is meant to describe implementation details
*Scanner: code-review/convention | *
<!-- compliance-fp:1acb160549025fd88d6b29d8f6cd72c12514fb1f1d5879bf2f42c24c38f014de -->
|
||||
|
||||
The Compliance Scanner automatically deduplicates findings across all scanning surfaces to prevent noise and duplicate issues.
|
||||
|
||||
## SAST Finding Dedup
|
||||
|
||||
Static analysis findings are deduplicated using SHA-256 fingerprints computed from:
|
||||
|
||||
- Repository ID
|
||||
- Scanner rule ID (e.g., Semgrep check ID)
|
||||
- File path
|
||||
- Line number
|
||||
|
||||
Before inserting a new finding, the pipeline checks if a finding with the same fingerprint already exists. If it does, the finding is skipped.
|
||||
|
||||
## DAST / Pentest Finding Dedup
|
||||
|
||||
Dynamic testing findings go through two-phase deduplication:
|
||||
|
||||
### Phase 1: Exact Dedup
|
||||
|
||||
Findings with the same canonicalized title, endpoint, and HTTP method are merged. Evidence from duplicate findings is combined into a single finding, keeping the highest severity.
|
||||
|
||||
**Title canonicalization** handles common variations:
|
||||
- Domain names and URLs are stripped from titles (e.g., "Missing HSTS header for example.com" becomes "Missing HSTS header")
|
||||
- Known synonyms are resolved (e.g., "HSTS" maps to "strict-transport-security", "CSP" maps to "content-security-policy")
|
||||
|
||||
### Phase 2: CWE-Based Dedup
|
||||
|
||||
After exact dedup, findings with the same CWE and endpoint are merged. This catches cases where different tools report the same underlying issue with different titles or vulnerability types (e.g., a missing HSTS header reported as both `security_header_missing` and `tls_misconfiguration`).
|
||||
|
||||
The primary finding is selected by highest severity, then most evidence, then longest description. Evidence from merged findings is preserved.
|
||||
|
||||
### When Dedup Applies
|
||||
|
||||
- **At insertion time**: During a pentest session, before each finding is stored in MongoDB
|
||||
- **At report export**: When generating a pentest report, all session findings are deduplicated before rendering
|
||||
|
||||
## PR Review Comment Dedup
|
||||
|
||||
PR review comments are deduplicated to prevent posting the same finding multiple times:
|
||||
|
||||
- Each comment includes a fingerprint computed from the repository, PR number, file path, line, and finding title
|
||||
- Within a single review run, duplicate findings are skipped
|
||||
- The fingerprint is embedded as an HTML comment in the review body for future cross-run dedup
|
||||
|
||||
## Issue Tracker Dedup
|
||||
|
||||
Before creating an issue in GitHub, GitLab, Jira, or Gitea, the scanner:
|
||||
|
||||
1. Searches for an existing issue matching the finding's fingerprint
|
||||
2. Falls back to searching by issue title
|
||||
3. Skips creation if a match is found
|
||||
|
||||
## Code Review Dedup
|
||||
|
||||
Multi-pass LLM code reviews (logic, security, convention, complexity) are deduplicated across passes using proximity-aware keys:
|
||||
|
||||
- Findings within 3 lines of each other on the same file with similar normalized titles are considered duplicates
|
||||
- The finding with the highest severity is kept
|
||||
- CWE information is merged from duplicates
|
||||
60
docs/features/help-chat.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Help Chat Assistant
|
||||
|
||||
The Help Chat is a floating assistant available on every page of the dashboard. It answers questions about the Compliance Scanner using the project documentation as its knowledge base.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. Click the **?** button in the bottom-right corner of any page
|
||||
2. Type your question and press Enter
|
||||
3. The assistant responds with answers grounded in the project documentation
|
||||
|
||||
The chat supports multi-turn conversations -- you can ask follow-up questions and the assistant will remember the context of your conversation.
|
||||
|
||||
## What You Can Ask
|
||||
|
||||
- **Getting started**: "How do I add a repository?" / "How do I trigger a scan?"
|
||||
- **Features**: "What is SBOM?" / "How does the code knowledge graph work?"
|
||||
- **Configuration**: "How do I set up webhooks?" / "What environment variables are needed?"
|
||||
- **Scanning**: "What does the scan pipeline do?" / "How does LLM triage work?"
|
||||
- **DAST & Pentesting**: "How do I run a pentest?" / "What DAST tools are available?"
|
||||
- **Integrations**: "How do I connect to GitHub?" / "What is MCP?"
|
||||
|
||||
## Technical Details
|
||||
|
||||
The help chat loads all project documentation (README, guides, feature docs, reference) at startup and caches them in memory. When you ask a question, it sends your message along with the full documentation context to the LLM via LiteLLM, which generates a grounded response.
|
||||
|
||||
### API Endpoint
|
||||
|
||||
```
|
||||
|
sharang
commented
[medium] Insecure Direct Object Reference in Help Chat API The Help Chat API endpoint (/api/v1/help/chat) accepts user messages and history without proper authentication or rate limiting. While this appears to be a frontend feature, if not properly secured, it could allow unauthorized users to query the LLM with arbitrary prompts, potentially leading to prompt injection or excessive API usage. Suggested fix: Implement proper authentication and authorization checks for the /api/v1/help/chat endpoint. Add rate limiting to prevent abuse and consider validating the message content to prevent prompt injection attacks. Scanner: code-review/security | CWE: CWE-285 **[medium] Insecure Direct Object Reference in Help Chat API**
The Help Chat API endpoint (/api/v1/help/chat) accepts user messages and history without proper authentication or rate limiting. While this appears to be a frontend feature, if not properly secured, it could allow unauthorized users to query the LLM with arbitrary prompts, potentially leading to prompt injection or excessive API usage.
Suggested fix: Implement proper authentication and authorization checks for the /api/v1/help/chat endpoint. Add rate limiting to prevent abuse and consider validating the message content to prevent prompt injection attacks.
*Scanner: code-review/security | CWE: CWE-285*
<!-- compliance-fp:09bc4a54933e346287fc4038614b67bfc4946b70f60e289a8ad948d3e42ae7aa -->
sharang
commented
[medium] Missing type annotations in API endpoint documentation The API endpoint documentation in help-chat.md lacks explicit type annotations for the request/response fields, which could make it harder for developers to understand expected data structures without referring to external code. Suggested fix: Add type annotations to the API endpoint schema (e.g., 'message: string', 'history: Array<{role: string, content: string}>') *Scanner: code-review/convention | * **[medium] Missing type annotations in API endpoint documentation**
The API endpoint documentation in help-chat.md lacks explicit type annotations for the request/response fields, which could make it harder for developers to understand expected data structures without referring to external code.
Suggested fix: Add type annotations to the API endpoint schema (e.g., 'message: string', 'history: Array<{role: string, content: string}>')
*Scanner: code-review/convention | *
<!-- compliance-fp:3e063ee07118dc0af12c2825dd37b47587616ff331a3c03a9b9e955c676ceda4 -->
|
||||
POST /api/v1/help/chat
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"message": "How do I add a repository?",
|
||||
"history": [
|
||||
{ "role": "user", "content": "previous question" },
|
||||
{ "role": "assistant", "content": "previous answer" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
sharang
commented
[medium] Hardcoded Default LiteLLM URL The documentation shows a hardcoded default value for LITELLM_URL ( Suggested fix: Remove hardcoded default values for sensitive configuration parameters. Ensure that production deployments require explicit configuration of these values and validate that they use secure protocols (HTTPS). Scanner: code-review/security | CWE: CWE-312 **[medium] Hardcoded Default LiteLLM URL**
The documentation shows a hardcoded default value for LITELLM_URL (`http://localhost:4000`) which could expose the system to man-in-the-middle attacks if not properly secured in production environments. This also indicates potential insecure defaults that should be reviewed.
Suggested fix: Remove hardcoded default values for sensitive configuration parameters. Ensure that production deployments require explicit configuration of these values and validate that they use secure protocols (HTTPS).
*Scanner: code-review/security | CWE: CWE-312*
<!-- compliance-fp:34523ae8522b8ba8a39e4f9beac2ccbb57f231de33de9431bdd0716f71c0f7b9 -->
|
||||
|
||||
### Configuration
|
||||
|
||||
|
sharang
commented
[high] Potential Command Injection via Documentation Loading The Help Chat assistant loads and caches documentation files at startup. If user-controlled input can influence which files are loaded or how they're processed, this could lead to command injection or arbitrary file access. The code doesn't show explicit file loading logic but the documentation mentions loading 'docs/features/' directory which could be vulnerable if paths are not properly sanitized. Suggested fix: Ensure all documentation file paths are properly validated and sanitized before being used. Implement strict path validation to prevent directory traversal attacks and ensure only intended documentation files are loaded. Scanner: code-review/security | CWE: CWE-78 **[high] Potential Command Injection via Documentation Loading**
The Help Chat assistant loads and caches documentation files at startup. If user-controlled input can influence which files are loaded or how they're processed, this could lead to command injection or arbitrary file access. The code doesn't show explicit file loading logic but the documentation mentions loading 'docs/features/' directory which could be vulnerable if paths are not properly sanitized.
Suggested fix: Ensure all documentation file paths are properly validated and sanitized before being used. Implement strict path validation to prevent directory traversal attacks and ensure only intended documentation files are loaded.
*Scanner: code-review/security | CWE: CWE-78*
<!-- compliance-fp:2cff713a203dcbbe3c60c0d4e3889bcccb13a607ecbbf2ee4e1f851600685d4e -->
|
||||
The help chat uses the same LiteLLM configuration as other LLM features:
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---------------------|-------------|---------|
|
||||
| `LITELLM_URL` | LiteLLM API base URL | `http://localhost:4000` |
|
||||
| `LITELLM_MODEL` | Model for chat responses | `gpt-4o` |
|
||||
| `LITELLM_API_KEY` | API key (optional) | -- |
|
||||
|
||||
### Documentation Sources
|
||||
|
||||
The assistant indexes the following documentation at startup:
|
||||
|
||||
- `README.md` -- Project overview and quick start
|
||||
- `docs/guide/` -- Getting started, repositories, findings, SBOM, scanning, issues, webhooks
|
||||
- `docs/features/` -- AI Chat, DAST, Code Graph, MCP Server, Pentesting, Help Chat
|
||||
- `docs/reference/` -- Glossary, tools reference
|
||||
|
||||
If documentation files are not found at startup (e.g., in a minimal Docker deployment), the assistant falls back to general knowledge about the project.
|
||||
@@ -1,8 +1,6 @@
|
||||
# Dashboard Overview
|
||||
|
||||
The Overview page is the landing page of Certifai. It gives you a high-level view of your security posture across all tracked repositories.
|
||||
|
||||

|
||||
The Overview page is the landing page of the Compliance Scanner. It gives you a high-level view of your security posture across all tracked repositories.
|
||||
|
sharang
commented
[medium] Inconsistent terminology between documentation files The term 'Compliance Scanner' is used in overview.md while 'Certifai' was previously used in the same location, indicating inconsistency in naming conventions across documentation files. Suggested fix: Standardize on 'Compliance Scanner' throughout the documentation to maintain consistency *Scanner: code-review/convention | * **[medium] Inconsistent terminology between documentation files**
The term 'Compliance Scanner' is used in overview.md while 'Certifai' was previously used in the same location, indicating inconsistency in naming conventions across documentation files.
Suggested fix: Standardize on 'Compliance Scanner' throughout the documentation to maintain consistency
*Scanner: code-review/convention | *
<!-- compliance-fp:f38e9b654734b539654c468273f62bb5bc3c068b3ff5d67b939d2f04e41fc7be -->
|
||||
|
||||
## Stats Cards
|
||||
|
||||
@@ -34,6 +32,10 @@ The overview includes quick-access cards for the AI Chat feature. Each card repr
|
||||
|
||||
If you have MCP servers registered, they appear on the overview page with their status and connection details. This lets you quickly check that your MCP integrations are running. See [MCP Integration](/features/mcp-server) for details.
|
||||
|
||||
## Help Chat Assistant
|
||||
|
||||
A floating help chat button is available in the bottom-right corner of every page. Click it to ask questions about the Compliance Scanner -- how to configure repositories, understand findings, set up webhooks, or use any feature. The assistant is grounded in the project documentation and uses LiteLLM for responses.
|
||||
|
||||
## Recent Scan Runs
|
||||
|
||||
The bottom section lists the most recent scan runs across all repositories, showing:
|
||||
|
||||
[medium] Inconsistent error handling in API endpoints
The API endpoints in the README show new functionality like '/api/v1/graph/:repo_id' and '/api/v1/chat/:repo_id' but don't specify how errors are handled. This suggests inconsistent error handling patterns compared to existing endpoints which likely follow a standard error response format.
Suggested fix: Add consistent error response examples for new API endpoints to maintain uniform error handling patterns across the API
*Scanner: code-review/convention | *