From 03d53f8b068e1381bcfeecb79705143566556963 Mon Sep 17 00:00:00 2001
From: Sharang Parnerkar
Date: Fri, 13 Mar 2026 09:10:36 +0100
Subject: [PATCH 1/2] ci: consolidate CI into single job; fix sidebar footer UI
- Merge fmt, clippy, audit, and tests into one job to eliminate
redundant cargo downloads and dependency compilation
- Update Rust version badge from 1.89 to 1.94 in README
- Redesign sidebar footer: circular avatar, stacked user info
with sign-out link, privacy/impressum footer links
Co-Authored-By: Claude Opus 4.6
---
.gitea/workflows/ci.yml | 98 ++++-----------
README.md | 4 +-
compliance-dashboard/assets/main.css | 115 +++++++++++++++++-
.../src/components/sidebar.rs | 33 +++--
4 files changed, 164 insertions(+), 86 deletions(-)
diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
index 785a911..3009a8e 100644
--- a/.gitea/workflows/ci.yml
+++ b/.gitea/workflows/ci.yml
@@ -23,10 +23,10 @@ concurrency:
jobs:
# ---------------------------------------------------------------------------
- # Stage 1: Code quality checks (run in parallel)
+ # Stage 1: Lint, audit, and test (single job to share cargo cache)
# ---------------------------------------------------------------------------
- fmt:
- name: Format
+ check:
+ name: Check
runs-on: docker
container:
image: rust:1.94-bookworm
@@ -37,105 +37,59 @@ jobs:
git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
git fetch --depth=1 origin "${GITHUB_SHA}"
git checkout FETCH_HEAD
- - run: rustup component add rustfmt
- # Format check does not compile, so sccache is not needed here.
- - run: cargo fmt --all --check
- env:
- RUSTC_WRAPPER: ""
-
- clippy:
- name: Clippy
- runs-on: docker
- container:
- image: rust:1.94-bookworm
- steps:
- - name: Checkout
- run: |
- git init
- git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
- git fetch --depth=1 origin "${GITHUB_SHA}"
- git checkout FETCH_HEAD
- - name: Install sccache
+ - name: Install tools
run: |
+ rustup component add rustfmt clippy
curl -fsSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \
| tar xz --strip-components=1 -C /usr/local/bin/ sccache-v0.9.1-x86_64-unknown-linux-musl/sccache
chmod +x /usr/local/bin/sccache
- - run: rustup component add clippy
- # Lint the agent (native only).
+ cargo install cargo-audit --locked
+ env:
+ RUSTC_WRAPPER: ""
+
+ # Format (no compilation needed)
+ - name: Format
+ run: cargo fmt --all --check
+ env:
+ RUSTC_WRAPPER: ""
+
+ # Clippy (compiles once, sccache reuses across feature sets)
- name: Clippy (agent)
run: cargo clippy -p compliance-agent -- -D warnings
- # Lint the dashboard for both feature sets independently.
- # sccache deduplicates shared crates between the two compilations.
- name: Clippy (dashboard server)
run: cargo clippy -p compliance-dashboard --features server --no-default-features -- -D warnings
- name: Clippy (dashboard web)
run: cargo clippy -p compliance-dashboard --features web --no-default-features -- -D warnings
- name: Clippy (mcp)
run: cargo clippy -p compliance-mcp -- -D warnings
- - name: Show sccache stats
- run: sccache --show-stats
- if: always()
- audit:
- name: Security Audit
- runs-on: docker
- if: github.ref == 'refs/heads/main'
- container:
- image: rust:1.94-bookworm
- steps:
- - name: Checkout
- run: |
- git init
- git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
- git fetch --depth=1 origin "${GITHUB_SHA}"
- git checkout FETCH_HEAD
- - run: cargo install cargo-audit
- env:
- RUSTC_WRAPPER: ""
- - run: cargo audit
+ # Security audit
+ - name: Security Audit
+ run: cargo audit
env:
RUSTC_WRAPPER: ""
- # ---------------------------------------------------------------------------
- # Stage 2: Tests (only after all quality checks pass)
- # ---------------------------------------------------------------------------
- test:
- name: Tests
- runs-on: docker
- needs: [fmt, clippy, audit]
- container:
- image: rust:1.94-bookworm
- steps:
- - name: Checkout
- run: |
- git init
- git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
- git fetch --depth=1 origin "${GITHUB_SHA}"
- git checkout FETCH_HEAD
- - name: Install sccache
- run: |
- curl -fsSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \
- | tar xz --strip-components=1 -C /usr/local/bin/ sccache-v0.9.1-x86_64-unknown-linux-musl/sccache
- chmod +x /usr/local/bin/sccache
- - name: Run tests (core + agent)
+ # Tests (reuses compilation artifacts from clippy)
+ - name: Tests (core + agent)
run: cargo test -p compliance-core -p compliance-agent
- - name: Run tests (dashboard server)
+ - name: Tests (dashboard server)
run: cargo test -p compliance-dashboard --features server --no-default-features
- - name: Run tests (dashboard web)
+ - name: Tests (dashboard web)
run: cargo test -p compliance-dashboard --features web --no-default-features
+
- name: Show sccache stats
run: sccache --show-stats
if: always()
# ---------------------------------------------------------------------------
- # Stage 3: Deploy (only on main, after tests pass)
+ # Stage 2: Deploy (only on main, after checks pass)
# Each service only deploys when its relevant files changed.
# ---------------------------------------------------------------------------
detect-changes:
name: Detect Changes
runs-on: docker
if: github.ref == 'refs/heads/main'
- needs: [test]
+ needs: [check]
container:
image: alpine:latest
outputs:
diff --git a/README.md b/README.md
index 698d9f9..c7da379 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
-
+
@@ -94,7 +94,7 @@ Compliance Scanner is an autonomous agent that continuously monitors git reposit
### Prerequisites
-- Rust 1.89+
+- Rust 1.94+
- [Dioxus CLI](https://dioxuslabs.com/learn/0.7/getting_started) (`dx`)
- MongoDB
- Docker & Docker Compose (optional)
diff --git a/compliance-dashboard/assets/main.css b/compliance-dashboard/assets/main.css
index 2470dbc..71f7e6b 100644
--- a/compliance-dashboard/assets/main.css
+++ b/compliance-dashboard/assets/main.css
@@ -262,13 +262,120 @@ code {
color: var(--accent);
}
-.sidebar-footer {
- padding: 14px 20px;
+.sidebar-spacer {
+ flex: 1;
+}
+
+.sidebar-user {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 12px 16px;
border-top: 1px solid var(--border);
- font-family: var(--font-mono);
+}
+
+.sidebar.collapsed .sidebar-user {
+ justify-content: center;
+ flex-direction: column;
+ gap: 6px;
+ padding: 12px 8px;
+}
+
+.user-avatar {
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, rgba(56, 189, 248, 0.2), rgba(139, 92, 246, 0.15));
+ border: 2px solid rgba(56, 189, 248, 0.2);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ transition: border-color 0.2s;
+}
+
+.user-avatar:hover {
+ border-color: rgba(56, 189, 248, 0.4);
+}
+
+.avatar-initials {
+ font-size: 14px;
+ font-weight: 700;
+ color: var(--accent);
+ line-height: 1;
+ text-transform: uppercase;
+}
+
+.avatar-img {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ object-fit: cover;
+}
+
+.user-info {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+}
+
+.user-name {
+ font-size: 13px;
+ font-weight: 600;
+ color: var(--text-primary);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.logout-link {
font-size: 11px;
color: var(--text-tertiary);
- letter-spacing: 0.02em;
+ text-decoration: none;
+ transition: color 0.15s;
+}
+
+.logout-link:hover {
+ color: #fca5a5;
+}
+
+.logout-btn-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--text-tertiary);
+ text-decoration: none;
+ transition: color 0.15s;
+}
+
+.logout-btn-icon:hover {
+ color: #fca5a5;
+}
+
+.sidebar-legal {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ padding: 8px 16px 14px;
+ font-size: 11px;
+}
+
+.sidebar-legal a {
+ color: var(--text-tertiary);
+ text-decoration: none;
+ transition: color 0.15s;
+}
+
+.sidebar-legal a:hover {
+ color: var(--text-secondary);
+}
+
+.legal-dot {
+ color: var(--text-tertiary);
+ opacity: 0.5;
}
.sidebar-toggle {
diff --git a/compliance-dashboard/src/components/sidebar.rs b/compliance-dashboard/src/components/sidebar.rs
index 4522fae..b8a3177 100644
--- a/compliance-dashboard/src/components/sidebar.rs
+++ b/compliance-dashboard/src/components/sidebar.rs
@@ -109,6 +109,8 @@ pub fn Sidebar() -> Element {
span { "Docs" }
}
}
+ // Spacer pushes footer to the bottom
+ div { class: "sidebar-spacer" }
button {
class: "sidebar-toggle",
onclick: move |_| collapsed.set(!collapsed()),
@@ -122,9 +124,8 @@ pub fn Sidebar() -> Element {
let auth_info = use_context::>();
let info = auth_info();
let initials = info.name.chars().next().unwrap_or('U').to_uppercase().to_string();
- let user_class = if collapsed() { "sidebar-user sidebar-user-collapsed" } else { "sidebar-user" };
rsx! {
- div { class: "{user_class}",
+ div { class: "sidebar-user",
div { class: "user-avatar",
if info.avatar_url.is_empty() {
span { class: "avatar-initials", "{initials}" }
@@ -133,13 +134,29 @@ pub fn Sidebar() -> Element {
}
}
if !collapsed() {
- span { class: "user-name", "{info.name}" }
+ div { class: "user-info",
+ span { class: "user-name", "{info.name}" }
+ a {
+ href: "/logout",
+ class: "logout-link",
+ "Sign out"
+ }
+ }
}
- a {
- href: "/logout",
- class: if collapsed() { "logout-btn logout-btn-collapsed" } else { "logout-btn" },
- title: "Sign out",
- Icon { icon: BsBoxArrowRight, width: 16, height: 16 }
+ if collapsed() {
+ a {
+ href: "/logout",
+ class: "logout-btn-icon",
+ title: "Sign out",
+ Icon { icon: BsBoxArrowRight, width: 14, height: 14 }
+ }
+ }
+ }
+ if !collapsed() {
+ div { class: "sidebar-legal",
+ a { href: "/privacy", "Privacy" }
+ span { class: "legal-dot", "ยท" }
+ a { href: "/impressum", "Impressum" }
}
}
}
--
2.49.1
From df9a20e768a5d460f352130142367832f8cd71a7 Mon Sep 17 00:00:00 2001
From: Sharang Parnerkar
Date: Fri, 13 Mar 2026 10:23:04 +0100
Subject: [PATCH 2/2] ci: prevent duplicate runs on PR branches
Only trigger on push to main and on pull_request events.
Previously push to any branch + pull_request both fired,
causing every PR push to run CI twice.
Co-Authored-By: Claude Opus 4.6
---
.gitea/workflows/ci.yml | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
index 3009a8e..d4b88bf 100644
--- a/.gitea/workflows/ci.yml
+++ b/.gitea/workflows/ci.yml
@@ -2,11 +2,9 @@ name: CI
on:
push:
- branches:
- - "**"
- pull_request:
branches:
- main
+ pull_request:
env:
CARGO_TERM_COLOR: always
--
2.49.1