Skip to content

feat: mvp-foundation architecture, ai providers, and secrets engine#1

Merged
chojuninengu merged 1 commit into
mainfrom
feat/mvp-foundation
Apr 2, 2026
Merged

feat: mvp-foundation architecture, ai providers, and secrets engine#1
chojuninengu merged 1 commit into
mainfrom
feat/mvp-foundation

Conversation

@chojuninengu
Copy link
Copy Markdown
Member

@chojuninengu chojuninengu commented Apr 2, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added multi-provider AI support for vulnerability explanations and code fix generation, supporting Anthropic, OpenAI, Google, and custom providers.
    • Implemented working secrets detection scanning engine.
    • Added new CLI flags for configurable AI provider, key, model, and endpoint configuration.
  • Chores

    • Migrated frontend framework from Next.js to SvelteKit.
    • Updated authentication configuration system.
    • Environment variable naming updates for streamlined configuration.
  • Documentation

    • Updated architecture documentation and added test fixture guidance.

@chojuninengu chojuninengu self-assigned this Apr 2, 2026
@chojuninengu chojuninengu merged commit af083de into main Apr 2, 2026
2 of 6 checks passed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 2, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e4f8092-87b7-404c-836c-4ca3fa3c806b

📥 Commits

Reviewing files that changed from the base of the PR and between e41a713 and 192f7a6.

📒 Files selected for processing (20)
  • .env.example
  • AGENTS.md
  • crates/cli/Cargo.toml
  • crates/cli/src/main.rs
  • crates/scanner/Cargo.toml
  • crates/scanner/src/ai/anthropic.rs
  • crates/scanner/src/ai/custom.rs
  • crates/scanner/src/ai/google.rs
  • crates/scanner/src/ai/mod.rs
  • crates/scanner/src/ai/openai.rs
  • crates/scanner/src/engine.rs
  • crates/scanner/src/engines/ai_code.rs
  • crates/scanner/src/engines/mod.rs
  • crates/scanner/src/engines/sast.rs
  • crates/scanner/src/engines/sca.rs
  • crates/scanner/src/engines/secrets.rs
  • crates/scanner/src/finding.rs
  • crates/scanner/src/lib.rs
  • test-fixtures/README.md
  • test-fixtures/vulnerable_app.py

📝 Walkthrough

Walkthrough

The pull request transitions the scanner from a single-provider Anthropic AI integration to a flexible multi-provider architecture supporting Anthropic, OpenAI, Google, and custom endpoints. It migrates framework dependencies from Next.js/NextAuth to SvelteKit and refactors the Rust scanner library to separate raw findings from AI-enriched findings, implementing working secrets detection and pluggable AI provider infrastructure.

Changes

Cohort / File(s) Summary
Environment & Documentation
.env.example, AGENTS.md, test-fixtures/README.md
Updated environment variables from Anthropic/NextAuth.js (with Next.js localhost:3000) to multi-provider AI config and SvelteKit auth (localhost:5173). Updated architecture docs reflecting SvelteKit frontend, domain types (ScanConfig, Engine), and multi-provider AI system.
CLI Integration
crates/cli/Cargo.toml, crates/cli/src/main.rs
Added walkdir dependency and reimplemented scan command with real scanning logic: file collection, per-file engine execution, severity filtering, and both JSON/formatted text output. Added AI configuration flags (ai_provider, ai_key, ai_model, ai_endpoint) with helper functions for config building and file collection.
AI Provider Framework
crates/scanner/Cargo.toml, crates/scanner/src/ai/mod.rs, crates/scanner/src/ai/anthropic.rs, crates/scanner/src/ai/openai.rs, crates/scanner/src/ai/google.rs, crates/scanner/src/ai/custom.rs
Introduced pluggable AI provider system with ProviderKind, AiConfig, and AiProvider trait. Implemented four concrete providers (Anthropic, OpenAI, Google, Custom) with HTTP-based API calls, error handling, and prompt-building utilities. Added async-trait dependency.
Scanner Core Refactoring
crates/scanner/src/lib.rs, crates/scanner/src/finding.rs, crates/scanner/src/engine.rs
Refactored scan API from per-parameter to ScanConfig struct; introduced RawFinding type for engine output and AI-enrichment pipeline that conditionally creates providers and enriches findings. Updated Engine enum definition location and orchestrator to delegate to individual engine modules.
Engine Implementations
crates/scanner/src/engines/mod.rs, crates/scanner/src/engines/sast.rs, crates/scanner/src/engines/sca.rs, crates/scanner/src/engines/secrets.rs, crates/scanner/src/engines/ai_code.rs
Unified engine signatures to accept &ScanConfig and return Vec<RawFinding>. Implemented working secrets detection engine with regex patterns and redaction logic. Stubbed AI code engine. Updated SAST/SCA stubs to new signature.
Test Fixtures
test-fixtures/vulnerable_app.py
Added Python test fixture with intentional hardcoded secrets (AWS keys, DB URL, Stripe key, GitHub token, private key) for scanner validation.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as CLI
    participant ScanEngine as Engine::run()
    participant SecretEngine as secrets::run()
    participant AIFactory as AI Factory
    participant Provider as AI Provider
    participant APIEndpoint as API Endpoint

    User->>CLI: scan with --ai_provider, --ai_key, etc.
    CLI->>ScanEngine: scan(config: &ScanConfig)
    ScanEngine->>SecretEngine: run(config)
    SecretEngine-->>ScanEngine: Vec<RawFinding>
    alt ai_config present
        ScanEngine->>AIFactory: create_provider(&ai_config)
        AIFactory-->>ScanEngine: Box<dyn AiProvider>
        loop for each RawFinding
            ScanEngine->>Provider: explain(&raw_finding)
            Provider->>APIEndpoint: POST /v1/chat/completions (or equiv)
            APIEndpoint-->>Provider: response text
            Provider-->>ScanEngine: explanation String
            ScanEngine->>Provider: generate_fix(&raw_finding)
            Provider->>APIEndpoint: POST /v1/chat/completions (or equiv)
            APIEndpoint-->>Provider: response text
            Provider-->>ScanEngine: fixed_code String
            ScanEngine->>ScanEngine: raw.into_finding(explanation, fixed_code)
        end
    else no ai_config
        loop for each RawFinding
            ScanEngine->>ScanEngine: raw.into_finding("", "")
        end
    end
    ScanEngine-->>CLI: Vec<Finding>
    CLI->>CLI: filter by severity, format output
    CLI-->>User: JSON or text report
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

The changes span heterogeneous areas: four new AI provider implementations with HTTP error handling, significant scanner core refactoring (API signature changes, new findings model with enrichment pipeline), working secrets detection logic with regex patterns, CLI rewrite with real scan orchestration, and environment variable migration across multiple configuration points. Logic density is moderate-to-high (trait implementations, async orchestration, error handling, prompt construction), and each AI provider requires independent verification of API contract correctness.

Poem

🐰 Hoppy news from Warren Code!

Multiple minds now help us scan,
Not just Claude, but OpenAI and friends—
From secrets found to fixes penned,
Our scanners bound by traits that blend,
SvelteKit's dawn and traits that stand.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mvp-foundation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Rust — fmt / clippy / test

Failed stage: Check formatting [❌]

Failed test name: ""

Failure summary:

The action failed during the formatting check step cargo fmt --all -- --check.
rustfmt detected that
some Rust files are not formatted according to the project’s style, so it printed diffs and exited
with code 1.
Diffs were reported in:
- /home/runner/work/Zenvra/Zenvra/crates/cli/src/main.rs
(around lines 246 and 277)
- /home/runner/work/Zenvra/Zenvra/crates/scanner/src/engines/secrets.rs
(around line 290)

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

144:  �[36;1mecho "components=$(for c in ${components//,/ }; do echo -n ' --component' $c; done)" >> $GITHUB_OUTPUT�[0m
145:  �[36;1mecho "downgrade=" >> $GITHUB_OUTPUT�[0m
146:  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
147:  env:
148:  targets: 
149:  components: rustfmt, clippy
150:  ##[endgroup]
151:  ##[group]Run : set $CARGO_HOME
152:  �[36;1m: set $CARGO_HOME�[0m
153:  �[36;1mecho CARGO_HOME=${CARGO_HOME:-"$HOME/.cargo"} >> $GITHUB_ENV�[0m
154:  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
155:  ##[endgroup]
156:  ##[group]Run : install rustup if needed
157:  �[36;1m: install rustup if needed�[0m
158:  �[36;1mif ! command -v rustup &>/dev/null; then�[0m
159:  �[36;1m  curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused --location --silent --show-error --fail https://sh.rustup.rs | sh -s -- --default-toolchain none -y�[0m
160:  �[36;1m  echo "$CARGO_HOME/bin" >> $GITHUB_PATH�[0m
...

218:  �[36;1mif [ -z "${CARGO_REGISTRIES_CRATES_IO_PROTOCOL+set}" -o -f "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol ]; then�[0m
219:  �[36;1m  if rustc +stable --version --verbose | grep -q '^release: 1\.6[89]\.'; then�[0m
220:  �[36;1m    touch "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol || true�[0m
221:  �[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse >> $GITHUB_ENV�[0m
222:  �[36;1m  elif rustc +stable --version --verbose | grep -q '^release: 1\.6[67]\.'; then�[0m
223:  �[36;1m    touch "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol || true�[0m
224:  �[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=git >> $GITHUB_ENV�[0m
225:  �[36;1m  fi�[0m
226:  �[36;1mfi�[0m
227:  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
228:  env:
229:  CARGO_HOME: /home/runner/.cargo
230:  CARGO_INCREMENTAL: 0
231:  CARGO_TERM_COLOR: always
232:  ##[endgroup]
233:  ##[group]Run : work around spurious network errors in curl 8.0
234:  �[36;1m: work around spurious network errors in curl 8.0�[0m
235:  �[36;1m# https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/timeout.20investigation�[0m
...

303:  - CARGO_INCREMENTAL
304:  - CARGO_TERM_COLOR
305:  .. Lockfiles considered:
306:  - /home/runner/work/Zenvra/Zenvra/crates/cli/Cargo.toml
307:  - /home/runner/work/Zenvra/Zenvra/crates/scanner/Cargo.toml
308:  ##[endgroup]
309:  ... Restoring cache ...
310:  No cache found.
311:  ##[group]Run cargo fmt --all -- --check
312:  �[36;1mcargo fmt --all -- --check�[0m
313:  shell: /usr/bin/bash -e {0}
314:  env:
315:  CARGO_HOME: /home/runner/.cargo
316:  CARGO_INCREMENTAL: 0
317:  CARGO_TERM_COLOR: always
318:  CACHE_ON_FAILURE: false
319:  ##[endgroup]
...

335:  -            .unwrap_or("");
336:  +        let ext = file_path.extension().and_then(|e| e.to_str()).unwrap_or("");
337:  let language = Language::from_extension(ext);
338:  let config = ScanConfig {
339:  Diff in /home/runner/work/Zenvra/Zenvra/crates/cli/src/main.rs:246:
340:  "openai" => ProviderKind::OpenAi,
341:  "google" => ProviderKind::Google,
342:  "custom" => ProviderKind::Custom,
343:  -        other => anyhow::bail!("Unknown AI provider: {other}. Use: anthropic, openai, google, custom"),
344:  +        other => {
345:  +            anyhow::bail!("Unknown AI provider: {other}. Use: anthropic, openai, google, custom")
346:  +        }
347:  };
348:  let model_name = model
349:  Diff in /home/runner/work/Zenvra/Zenvra/crates/cli/src/main.rs:277:
350:  std::fs::read_to_string(path).context(format!("Failed to read {}", path.display()))?;
351:  files.push((path.clone(), content));
...

449:  -        .await;
450:  +        let findings = scan_code("fn main() {\n    println!(\"Hello, world!\");\n}").await;
451:  assert!(findings.is_empty());
452:  }
453:  Diff in /home/runner/work/Zenvra/Zenvra/crates/scanner/src/engines/secrets.rs:290:
454:  #[test]
455:  fn redact_works() {
456:  -        assert_eq!(redact_secret("AKIAIOSFODNN7EXAMPLE"), "AKIA************…MPLE");
457:  +        assert_eq!(
458:  +            redact_secret("AKIAIOSFODNN7EXAMPLE"),
459:  +            "AKIA************…MPLE"
460:  +        );
461:  assert_eq!(redact_secret("short"), "*****");
462:  }
463:  }
464:  ##[error]Process completed with exit code 1.
465:  Post job cleanup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant