diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 785a911..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 @@ -23,10 +21,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 +35,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::