Initial commit: Compliance Scanner Agent

Autonomous security and compliance scanning agent for git repositories.
Features: SAST (Semgrep), SBOM (Syft), CVE monitoring (OSV.dev/NVD),
GDPR/OAuth pattern detection, LLM triage, issue creation (GitHub/GitLab/Jira),
PR reviews, and Dioxus fullstack dashboard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-03-02 13:30:17 +01:00
commit 0867e401bc
97 changed files with 11750 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
use dioxus::prelude::*;
use crate::app::Route;
use crate::components::sidebar::Sidebar;
#[component]
pub fn AppShell() -> Element {
rsx! {
div { class: "app-shell",
Sidebar {}
main { class: "main-content",
Outlet::<Route> {}
}
}
}
}

View File

@@ -0,0 +1,23 @@
use dioxus::prelude::*;
#[component]
pub fn CodeSnippet(
code: String,
#[props(default)] file_path: String,
#[props(default)] line_number: u32,
) -> Element {
rsx! {
div {
if !file_path.is_empty() {
div {
style: "font-size: 12px; color: var(--text-secondary); margin-bottom: 4px; font-family: monospace;",
"{file_path}"
if line_number > 0 {
":{line_number}"
}
}
}
pre { class: "code-block", "{code}" }
}
}
}

View File

@@ -0,0 +1,7 @@
pub mod app_shell;
pub mod code_snippet;
pub mod page_header;
pub mod pagination;
pub mod severity_badge;
pub mod sidebar;
pub mod stat_card;

View File

@@ -0,0 +1,13 @@
use dioxus::prelude::*;
#[component]
pub fn PageHeader(title: String, #[props(default)] description: String) -> Element {
rsx! {
div { class: "page-header",
h2 { "{title}" }
if !description.is_empty() {
p { "{description}" }
}
}
}
}

View File

@@ -0,0 +1,33 @@
use dioxus::prelude::*;
#[component]
pub fn Pagination(
current_page: u64,
total_pages: u64,
on_page_change: EventHandler<u64>,
) -> Element {
if total_pages <= 1 {
return rsx! {};
}
rsx! {
div { class: "pagination",
button {
class: "btn btn-ghost",
disabled: current_page <= 1,
onclick: move |_| on_page_change.call(current_page.saturating_sub(1)),
"Previous"
}
span {
style: "color: var(--text-secondary); font-size: 14px;",
"Page {current_page} of {total_pages}"
}
button {
class: "btn btn-ghost",
disabled: current_page >= total_pages,
onclick: move |_| on_page_change.call(current_page + 1),
"Next"
}
}
}
}

View File

@@ -0,0 +1,16 @@
use dioxus::prelude::*;
#[component]
pub fn SeverityBadge(severity: String) -> Element {
let class = match severity.to_lowercase().as_str() {
"critical" => "badge badge-critical",
"high" => "badge badge-high",
"medium" => "badge badge-medium",
"low" => "badge badge-low",
_ => "badge badge-info",
};
rsx! {
span { class: class, "{severity}" }
}
}

View File

@@ -0,0 +1,81 @@
use dioxus::prelude::*;
use dioxus_free_icons::icons::bs_icons::*;
use dioxus_free_icons::Icon;
use crate::app::Route;
struct NavItem {
label: &'static str,
route: Route,
icon: Element,
}
#[component]
pub fn Sidebar() -> Element {
let current_route = use_route::<Route>();
let nav_items = [
NavItem {
label: "Overview",
route: Route::OverviewPage {},
icon: rsx! { Icon { icon: BsSpeedometer2, width: 18, height: 18 } },
},
NavItem {
label: "Repositories",
route: Route::RepositoriesPage {},
icon: rsx! { Icon { icon: BsFolder2Open, width: 18, height: 18 } },
},
NavItem {
label: "Findings",
route: Route::FindingsPage {},
icon: rsx! { Icon { icon: BsShieldExclamation, width: 18, height: 18 } },
},
NavItem {
label: "SBOM",
route: Route::SbomPage {},
icon: rsx! { Icon { icon: BsBoxSeam, width: 18, height: 18 } },
},
NavItem {
label: "Issues",
route: Route::IssuesPage {},
icon: rsx! { Icon { icon: BsListTask, width: 18, height: 18 } },
},
NavItem {
label: "Settings",
route: Route::SettingsPage {},
icon: rsx! { Icon { icon: BsGear, width: 18, height: 18 } },
},
];
rsx! {
nav { class: "sidebar",
div { class: "sidebar-header",
Icon { icon: BsShieldCheck, width: 24, height: 24 }
h1 { "Compliance Scanner" }
}
div { class: "sidebar-nav",
for item in nav_items {
{
let is_active = match (&current_route, &item.route) {
(Route::FindingDetailPage { .. }, Route::FindingsPage {}) => true,
(a, b) => a == b,
};
let class = if is_active { "nav-item active" } else { "nav-item" };
rsx! {
Link {
to: item.route.clone(),
class: class,
{item.icon}
span { "{item.label}" }
}
}
}
}
}
div {
style: "padding: 16px; border-top: 1px solid var(--border); font-size: 12px; color: var(--text-secondary);",
"v0.1.0"
}
}
}
}

View File

@@ -0,0 +1,21 @@
use dioxus::prelude::*;
#[component]
pub fn StatCard(
label: String,
value: String,
#[props(default)] color: String,
) -> Element {
let value_style = if color.is_empty() {
String::new()
} else {
format!("color: {color}")
};
rsx! {
div { class: "stat-card",
div { class: "label", "{label}" }
div { class: "value", style: value_style, "{value}" }
}
}
}