Skip to content

chore(security): enforce secret gates and add E2E secret-filter QA#39

Merged
Mehdi-Bl merged 6 commits into
mainfrom
chore/secret-gates-verify
Feb 9, 2026
Merged

chore(security): enforce secret gates and add E2E secret-filter QA#39
Mehdi-Bl merged 6 commits into
mainfrom
chore/secret-gates-verify

Conversation

@Mehdi-Bl

@Mehdi-Bl Mehdi-Bl commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • enforce staged secret scanning in local hooks on Linux/macOS and Windows
  • add gitleaks:staged command wiring (gitleaks protect --staged)
  • strengthen .pre-commit-config.yaml coverage (ts/tsx + gitleaks hook)
  • add E2E assertions in qa:screenshot for secret filtering behavior:
    • secret files hidden by default
    • secret files appear when secret-filter toggles are disabled in Config tab
  • update tests/catalog.md with the new screenshot-gate use case

Validation

  • npm run lint
  • npm test -- --runInBand
  • npm run qa:screenshot
  • make sonar (local scan succeeded)

Notes

  • added repository ruleset requiring status check Gitleaks Secret Scan on default branch
  • no secrets/hostnames are intentionally included in this PR description

Summary by CodeRabbit

  • New Features

    • Secret scanning added to detect and hide sensitive files and secret patterns; two new config options to enable scanning and exclude suspicious files; UI toggles added.
  • Bug Fixes

    • Pre-commit flow updated to run a staged secret check and exit early on errors to better prevent committing secrets.
  • Tests

    • New unit and integration tests covering secret detection, filtering behavior, config persistence, and security command validation.

@sourcery-ai

sourcery-ai Bot commented Feb 9, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds configurable secret-scanning and suspicious-file exclusion across file filtering and analysis, wires gitleaks staged scanning into local tooling and hooks, and extends automated tests and E2E screenshot QA to cover the new secret-filtering behavior and config toggles.

Sequence diagram for secret filtering from config toggles to file tree

sequenceDiagram
  actor User
  participant ConfigTab
  participant LocalStorage
  participant SourceTab
  participant RendererFileService as RendererFileService
  participant ElectronAPI as ElectronAPI_getDirectoryTree
  participant SecretScanner

  User->>ConfigTab: Open Config tab
  ConfigTab->>LocalStorage: Load existing configContent
  User->>ConfigTab: Uncheck enable_secret_scanning and exclude_suspicious_files
  User->>ConfigTab: Click Save config
  ConfigTab->>ConfigTab: saveConfig()
  ConfigTab->>LocalStorage: setItem(configContent)

  User->>SourceTab: Switch to Source tab
  User->>SourceTab: Click Refresh file list
  SourceTab->>RendererFileService: refreshFiles()
  RendererFileService->>LocalStorage: getItem(configContent)
  RendererFileService->>ElectronAPI: getDirectoryTree(rootPath, configContent)

  ElectronAPI->>ElectronAPI: determine excludeSensitiveFiles flag
  ElectronAPI->>SecretScanner: isSensitiveFilePath(itemPath) for each file
  alt excludeSensitiveFiles is false
    SecretScanner-->>ElectronAPI: false for secret files
    ElectronAPI-->>RendererFileService: directory tree including secret files
  else excludeSensitiveFiles is true
    SecretScanner-->>ElectronAPI: true for secret files
    ElectronAPI-->>RendererFileService: directory tree without secret files
  end

  RendererFileService-->>SourceTab: Rendered file tree
  SourceTab-->>User: Secret files visible or hidden depending on config
Loading

Class diagram for secret scanning utilities and config integration

classDiagram
  class ConfigObject {
    +boolean~optional~ use_custom_excludes
    +boolean~optional~ use_custom_includes
    +boolean~optional~ use_gitignore
    +boolean~optional~ enable_secret_scanning
    +boolean~optional~ exclude_suspicious_files
    +boolean~optional~ include_tree_view
    +boolean~optional~ show_token_count
  }

  class SecretMatch {
    +string id
    +string description
  }

  class SecretScanResult {
    +boolean isSuspicious
    +SecretMatch[] matches
  }

  class SecretScanner {
    +shouldExcludeSuspiciousFiles(config: ConfigObject) boolean
    +isSensitiveFilePath(filePath: string) boolean
    +scanContentForSecrets(content: string) SecretScanResult
    +scanFileForSecrets(filePath: string) SecretScanResult
  }

  class FileAnalyzer {
    -ConfigObject config
    +analyzeFile(filePath: string) number
  }

  class FilterUtils {
    +shouldExclude(itemPath: string, isDirectory: boolean, config: ConfigObject, includePatterns: string[], excludePatterns: string[]) boolean
  }

  class ConfigTab {
    -boolean useCustomExcludes
    -boolean useCustomIncludes
    -boolean useGitignore
    -boolean enableSecretScanning
    -boolean excludeSuspiciousFiles
    -boolean includeTreeView
    -boolean showTokenCount
    -string fileExtensions
    +saveConfig() void
    +onConfigChange(configContent: string) void
  }

  SecretScanner <.. ConfigObject : uses
  FileAnalyzer --> ConfigObject : has
  FileAnalyzer ..> SecretScanner : uses
  FilterUtils ..> SecretScanner : uses
  FilterUtils --> ConfigObject : uses
  ConfigTab --> ConfigObject : builds
  ConfigTab ..> SecretScanner : controls via flags
Loading

File-Level Changes

Change Details Files
Introduce centralized secret-scanning utilities and integrate them into path filtering and file analysis so suspicious files are excluded by default but can be re-enabled via config toggles.
  • Add secret-scanner utility with path-based sensitivity detection, regex-based content scanning, and safe file-scanning helpers
  • Use secret-scanner in filter-utils.shouldExclude to drop sensitive files when secret filtering is enabled
  • Use secret-scanner in FileAnalyzer.analyzeFile to skip suspicious files before token counting based on config flags
  • Extend ConfigObject, default config, and config fixtures with enable_secret_scanning and exclude_suspicious_files flags
src/utils/secret-scanner.ts
src/utils/filter-utils.ts
src/utils/file-analyzer.ts
src/types/ipc.ts
src/utils/config.default.yaml
tests/fixtures/configs/default.yaml
Expose new secret-filter configuration in the UI and verify its behavior via unit tests and visual QA, including toggling filters to reveal hidden secret files.
  • Extend ConfigTab state, initialization, and serialization to handle enable_secret_scanning and exclude_suspicious_files
  • Render two new checkboxes in ConfigTab for scanning content for secrets and excluding suspicious files
  • Update ConfigTab tests to assert default-checked state of new toggles
  • Augment screenshot capture script to model secret files, apply mock directory-tree filtering tied to config toggles, and add E2E steps that assert secret files are hidden by default and appear when filters are disabled
src/renderer/components/ConfigTab.tsx
tests/unit/components/config-tab.test.tsx
scripts/capture-ui-screenshot.js
tests/catalog.md
Strengthen backend secret-handling behavior and test coverage to ensure suspicious files are skipped during repo analysis unless secret filtering is explicitly disabled.
  • Add integration test for repo:analyze to confirm suspicious files are omitted from filesInfo when secret scanning is enabled
  • Add unit tests for filter-utils to cover default exclusion of sensitive files and behavior when secret scanning is disabled
  • Add FileAnalyzer unit test to verify suspicious files are skipped and token counting is bypassed when a secret is detected
tests/integration/main-process/handlers.test.ts
tests/unit/utils/filter-utils.test.ts
tests/unit/file-analyzer.test.ts
Enforce gitleaks staged scanning in local workflows and expose a dedicated command wrapper for it.
  • Implement runGitleaksStaged helper to call gitleaks protect --staged with appropriate environment and error handling
  • Wire gitleaks-staged/gitleaks:staged subcommands through the scripts CLI and package.json scripts
  • Invoke gitleaks:staged from Husky pre-commit hooks on Windows and POSIX shells so staged secrets fail the commit
scripts/lib/security.js
scripts/index.js
package.json
.husky/pre-commit.bat
.husky/pre-commit
Broaden pre-commit linting/formatting scope and add gitleaks to pre-commit hooks for additional static secret scanning.
  • Update eslint pre-commit hook to lint TS/TSX files as well as JS/JSX
  • Update prettier pre-commit hook to format TS/TSX along with existing file types
  • Add gitleaks repository and hook configuration to pre-commit
.pre-commit-config.yaml
Add focused unit tests for the new secret-scanning utilities and document their coverage in the test catalog.
  • Create secret-scanner unit tests covering path sensitivity detection, content scanning rules, file scanning error handling, and config-driven toggles
  • Update tests catalog to list secret-scanner coverage and to describe the screenshot QA command’s secret-filter behavior use case
tests/unit/utils/secret-scanner.test.ts
tests/catalog.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

github-actions Bot commented Feb 9, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a secret-scanning subsystem (rules, file/content scanners, path heuristics), config flags and UI toggles, integrates scanning into file analysis and filtering, adds staged gitleaks pre-commit invocation and CLI wiring, updates QA mocks, and introduces unit/integration tests.

Changes

Cohort / File(s) Summary
Pre-commit hooks & CLI
\.husky/pre-commit, \.husky/pre-commit.bat, package.json, scripts/index.js, scripts/lib/security.js
Pre-commit now invokes gitleaks:staged; batch script adds immediate error handling; new npm scripts and runGitleaksStaged() implemented with Windows-safe command validation and exports.
Secret scanning core
src/utils/secret-scanner.ts
New secret-scanner module: rule set, content/file scanners, path-sensitivity helpers, policy-aware scan APIs and types (SecretMatch, SecretScanResult, SECRET_RULES).
Config, types & defaults
src/types/ipc.ts, src/utils/config.default.yaml, tests/fixtures/configs/default.yaml
Adds enable_secret_scanning and exclude_suspicious_files config flags to types, default YAML, and test fixtures.
File analysis & filtering
src/utils/file-analyzer.ts, src/utils/filter-utils.ts
Integrates secret scan into analyzeFile (early-return for suspicious files), adds isBinaryFile export, and adds pre-check to exclude sensitive paths via secret-scanner.
UI configuration
src/renderer/components/ConfigTab.tsx
Adds UI state, setters, and two checkboxes for secret scanning and suspicious-file exclusion; wires persistence and config serialization (enable_secret_scanning, exclude_suspicious_files).
QA screenshot & mocks
scripts/capture-ui-screenshot.js
Mocks and renderer context extended to support filtered/unfiltered directory trees, selectors added to toggle and verify secret-file visibility in screenshot flows.
Pre-commit tooling config
.pre-commit-config.yaml
Extends ESLint/Prettier globs to include .ts/.tsx and adds a gitleaks hook entry.
Tests & catalog
tests/unit/utils/secret-scanner.test.ts, tests/unit/utils/filter-utils.test.ts, tests/unit/file-analyzer.test.ts, tests/unit/components/config-tab.test.tsx, tests/unit/scripts/security.test.js, tests/integration/main-process/handlers.test.ts, tests/fixtures/configs/default.yaml, tests/catalog.md
Adds comprehensive unit and integration tests for secret-scanner rules, file-analyzer early-exit behavior, filter-utils sensitive-path logic, ConfigTab toggles persistence, and security executable/path validations; updates catalog entries.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as "ConfigTab (UI)"
    participant Analyzer as "FileAnalyzer"
    participant Scanner as "SecretScanner"
    participant Filter as "FilterUtils"
    participant FS as "Filesystem"
    participant CLI as "gitleaks (scripts/lib/security)"

    User->>UI: toggle enable_secret_scanning / exclude_suspicious_files
    UI->>UI: persist config (enable_secret_scanning, exclude_suspicious_files)
    Note over Analyzer,Scanner: File analysis flow
    Analyzer->>FS: read file content
    FS-->>Analyzer: content
    Analyzer->>Scanner: scanContentForSecrets(content, config)
    Scanner-->>Analyzer: SecretScanResult {isSuspicious, matches}
    alt isSuspicious and exclude_suspicious_files enabled
        Analyzer->>Filter: shouldExclude(itemPath, config)
        Filter-->>Analyzer: true
        Analyzer-->>Analyzer: return null (skip further analysis)
    else not suspicious or exclusion disabled
        Analyzer-->>Analyzer: continue tokenization/analysis
        Analyzer-->>User: analysis result
    end
    Note over CLI,Scanner: pre-commit staged check
    CLI->>Scanner: runGitleaksStaged() (protect --staged --redact --no-banner --verbose --exit-code 1)
    Scanner-->>CLI: exit code / report
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐇 I hop through code and sniff the night,
I find the tokens hid from sight,
I hide the secrets, flag what's cracked,
Stage-safe commits — a tidy stack,
Hooray — the repo sleeps polite!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main changes: enforcing secret detection gates and adding QA test coverage for secret filtering functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/secret-gates-verify

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
src/utils/secret-scanner.ts (1)

67-76: Consider whether .pub key files should be flagged as sensitive.

Line 69 matches id_rsa.pub, id_ed25519.pub, etc. Public keys are not secrets — flagging them may cause unnecessary filtering of harmless files. If the intent is to be conservative, consider at least documenting this as a deliberate choice.

scripts/capture-ui-screenshot.js (1)

346-356: Regex-based YAML parsing in mock is fragile but acceptable for controlled test input.

The regex checks for enable_secret_scanning: false and exclude_suspicious_files: false work for the test's controlled config strings, but would break on edge cases like extra whitespace or comments. Since this is a mock E2E environment with predictable config shapes, this is fine — just be mindful if the config format evolves.


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-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Add secret scanning and suspicious file filtering with E2E QA verification

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Add secret scanning and suspicious file filtering with configurable toggles
• Implement pattern-based secret detection (GitHub tokens, AWS keys, private keys, etc.)
• Integrate secret filtering into file analysis and directory tree filtering
• Add E2E tests verifying secret files hidden by default and visible when disabled
• Enforce staged secret scanning in pre-commit hooks (gitleaks) on all platforms
Diagram
flowchart LR
  A["Config UI"] -->|enable_secret_scanning| B["Secret Scanner"]
  A -->|exclude_suspicious_files| B
  B -->|scanContentForSecrets| C["Pattern Detection"]
  B -->|isSensitiveFilePath| D["Path Analysis"]
  C -->|matches found| E["Skip File"]
  D -->|sensitive detected| E
  E -->|filtered tree| F["File Analyzer"]
  G["Pre-commit Hook"] -->|gitleaks:staged| H["Staged Files Check"]
  H -->|blocks secrets| I["Commit Prevention"]
Loading

Grey Divider

File Changes

1. src/types/ipc.ts ⚙️ Configuration changes +2/-0

Add secret scanning config options

src/types/ipc.ts


2. src/utils/secret-scanner.ts ✨ Enhancement +128/-0

New secret detection and filtering module

src/utils/secret-scanner.ts


3. src/utils/file-analyzer.ts ✨ Enhancement +10/-0

Integrate secret scanning into file analysis

src/utils/file-analyzer.ts


View more (17)
4. src/utils/filter-utils.ts ✨ Enhancement +5/-0

Add sensitive path filtering logic

src/utils/filter-utils.ts


5. src/renderer/components/ConfigTab.tsx ✨ Enhancement +54/-0

Add secret scanning UI toggles

src/renderer/components/ConfigTab.tsx


6. src/utils/config.default.yaml ⚙️ Configuration changes +2/-0

Enable secret scanning by default

src/utils/config.default.yaml


7. tests/unit/utils/secret-scanner.test.ts 🧪 Tests +94/-0

Comprehensive secret scanner unit tests

tests/unit/utils/secret-scanner.test.ts


8. tests/unit/file-analyzer.test.ts 🧪 Tests +11/-0

Add suspicious file skipping test

tests/unit/file-analyzer.test.ts


9. tests/unit/utils/filter-utils.test.ts 🧪 Tests +22/-0

Add sensitive file exclusion tests

tests/unit/utils/filter-utils.test.ts


10. tests/unit/components/config-tab.test.tsx 🧪 Tests +4/-0

Add secret scanning toggle tests

tests/unit/components/config-tab.test.tsx


11. tests/integration/main-process/handlers.test.ts 🧪 Tests +27/-0

Add E2E secret filtering integration test

tests/integration/main-process/handlers.test.ts


12. scripts/capture-ui-screenshot.js 🧪 Tests +115/-3

Add secret filter toggle E2E verification

scripts/capture-ui-screenshot.js


13. scripts/index.js ✨ Enhancement +5/-0

Add gitleaks-staged command routing

scripts/index.js


14. scripts/lib/security.js ✨ Enhancement +27/-0

Implement staged gitleaks scanning

scripts/lib/security.js


15. .husky/pre-commit ⚙️ Configuration changes +1/-2

Enforce gitleaks:staged in pre-commit hook

.husky/pre-commit


16. .husky/pre-commit.bat ⚙️ Configuration changes +3/-0

Enforce gitleaks:staged on Windows

.husky/pre-commit.bat


17. .pre-commit-config.yaml ⚙️ Configuration changes +7/-2

Add gitleaks hook and expand linting scope

.pre-commit-config.yaml


18. package.json ⚙️ Configuration changes +1/-0

Add gitleaks:staged npm script

package.json


19. tests/fixtures/configs/default.yaml ⚙️ Configuration changes +2/-0

Update test config with secret scanning

tests/fixtures/configs/default.yaml


20. tests/catalog.md 📝 Documentation +4/-3

Document secret scanner test coverage

tests/catalog.md


Grey Divider

Qodo Logo

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @Mehdi-Bl, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly bolsters the application's security posture by integrating robust secret detection directly into the development workflow via pre-commit hooks and enhancing the user interface with configurable secret filtering options. It also introduces new end-to-end tests to ensure these security features function as expected, preventing accidental exposure of sensitive information and improving overall code integrity.

Highlights

  • Enhanced Secret Scanning: Implemented staged secret scanning in local pre-commit hooks for both Linux/macOS and Windows environments, leveraging gitleaks to prevent secrets from being committed.
  • End-to-End QA for Secret Filtering: Added comprehensive end-to-end assertions within the UI screenshot capture process to validate the application's secret filtering behavior. This ensures sensitive files are hidden by default and correctly reappear when filtering toggles are disabled in the configuration.
  • UI Configuration for Secret Scanning: Introduced new UI toggles in the configuration tab, allowing users to enable/disable secret scanning and the exclusion of suspicious files, providing greater control over security features.
  • New Secret Scanner Utility: A new utility (secret-scanner.ts) has been added to identify sensitive file paths and scan file content for common secret patterns, integrating this logic into the file analysis and filtering processes.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .husky/pre-commit
    • Updated the pre-commit hook to use npm run gitleaks:staged for staged secret scanning.
  • .husky/pre-commit.bat
    • Modified the Windows pre-commit script to include npm run gitleaks:staged and added error handling to ensure script exits on failure.
  • .pre-commit-config.yaml
    • Expanded eslint and prettier hooks to cover TypeScript/TSX files.
    • Integrated gitleaks as a pre-commit hook to scan for secrets.
  • package.json
    • Added a new npm script gitleaks:staged to run staged gitleaks checks.
  • scripts/capture-ui-screenshot.js
    • Introduced mock sensitive files (.env, .npmrc) into the UI mock directory tree.
    • Added logic to simulate filtering of sensitive files based on configuration settings for UI testing.
    • Implemented new UI selectors and test steps to verify secret file visibility based on secret scanning toggles.
  • scripts/index.js
    • Added command wiring for gitleaks-staged to the main script executor.
  • scripts/lib/security.js
    • Implemented runGitleaksStaged function to execute gitleaks protect --staged.
  • src/renderer/components/ConfigTab.tsx
    • Added state management and UI elements for enable_secret_scanning and exclude_suspicious_files configuration options.
  • src/types/ipc.ts
    • Extended ConfigObject interface with enable_secret_scanning and exclude_suspicious_files properties.
  • src/utils/config.default.yaml
    • Added default settings for enable_secret_scanning: true and exclude_suspicious_files: true.
  • src/utils/file-analyzer.ts
    • Integrated secret scanning into the file analysis process to skip suspicious files if configured.
  • src/utils/filter-utils.ts
    • Updated file filtering logic to exclude sensitive file paths by default when secret scanning is enabled.
  • src/utils/secret-scanner.ts
    • Added a new utility file containing rules and functions for detecting sensitive file paths and secret patterns within file content.
  • tests/catalog.md
    • Updated the test catalog to include the new secret-scanner unit tests and expanded the qa:screenshot use cases.
  • tests/fixtures/configs/default.yaml
    • Updated default configuration fixture to include new secret scanning settings.
  • tests/integration/main-process/handlers.test.ts
    • Added an integration test to confirm that the repo:analyze handler correctly skips suspicious files during analysis.
  • tests/unit/components/config-tab.test.tsx
    • Added unit tests to verify the default state and functionality of the new secret scanning toggles in the ConfigTab.
  • tests/unit/file-analyzer.test.ts
    • Added a unit test to ensure FileAnalyzer skips suspicious files when secret scanning is active.
  • tests/unit/utils/filter-utils.test.ts
    • Added unit tests to confirm sensitive files are excluded by default and can be explicitly allowed by disabling secret scanning.
  • tests/unit/utils/secret-scanner.test.ts
    • Added a new unit test file to thoroughly test the secret-scanner utility's functions for path sensitivity, content scanning, and configuration handling.
Activity
  • The pull request includes various validation steps, such as lint, test, qa:screenshot, and sonar scans, indicating thorough testing.
  • A branch-level repository ruleset has been implemented to mandate the qa:screenshot status check on the default branch, ensuring visual regression tests are always run.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 4 issues, and left some high level feedback:

  • The sensitive-file detection logic is duplicated (and slightly divergent) between scripts/capture-ui-screenshot.js (both isSensitiveMockPath/cloneAndFilterMockTree and the inline cloneAndFilter in getDirectoryTree) and src/utils/secret-scanner.ts; consider reusing the shared helpers from secret-scanner or at least a single helper in the script to avoid future drift.
  • The decision logic for when to exclude suspicious files now lives in multiple places (shouldExcludeSuspiciousFiles + isSensitiveFilePath in filter-utils and content scanning in file-analyzer); it may be worth centralizing the policy (path vs content, and how the two toggles interact) into secret-scanner to keep behavior consistent as rules evolve.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The sensitive-file detection logic is duplicated (and slightly divergent) between `scripts/capture-ui-screenshot.js` (both `isSensitiveMockPath`/`cloneAndFilterMockTree` and the inline `cloneAndFilter` in `getDirectoryTree`) and `src/utils/secret-scanner.ts`; consider reusing the shared helpers from `secret-scanner` or at least a single helper in the script to avoid future drift.
- The decision logic for when to exclude suspicious files now lives in multiple places (`shouldExcludeSuspiciousFiles` + `isSensitiveFilePath` in `filter-utils` and content scanning in `file-analyzer`); it may be worth centralizing the policy (path vs content, and how the two toggles interact) into `secret-scanner` to keep behavior consistent as rules evolve.

## Individual Comments

### Comment 1
<location> `scripts/capture-ui-screenshot.js:346-355` </location>
<code_context>
+        getDirectoryTree: async (_dirPath, configContent) => {
</code_context>

<issue_to_address>
**suggestion:** Secret filtering logic is duplicated and slightly reimplemented inside `getDirectoryTree`.

By reintroducing `cloneAndFilter` here with its own “is this sensitive?” checks, this logic can easily drift from `isSensitiveMockPath` / `cloneAndFilterMockTree` and from what the renderer uses. Please refactor to use a single shared filtering implementation (or delegate to the renderer’s logic) so the mock behavior stays consistent and easier to maintain.

Suggested implementation:

```javascript
      window.electronAPI = {
        getDefaultConfig: async () => mockConfig,
        selectDirectory: async () => mockRootPath,
        getDirectoryTree: async (_dirPath, configContent) => {
          const activeConfig =
            typeof configContent === 'string' && configContent.trim()
              ? configContent
              : localStorage.getItem('configContent') || '';

          const excludeSensitiveFiles =
            !/(^|\n)\s*enable_secret_scanning\s*:\s*false\b/i.test(activeConfig) &&
            !/(^|\n)\s*exclude_suspicious_files\s*:\s*false\b/i.test(activeConfig);

          // Delegate to the shared mock tree filtering logic so behavior matches the renderer.
          return cloneAndFilterMockTree({
            excludeSensitiveFiles,
            configContent: activeConfig,
          });

```

I’m assuming there is an existing shared helper like `cloneAndFilterMockTree` (and likely `isSensitiveMockPath`) used elsewhere in this file or in related test helpers. If the name or signature differs, adjust the call accordingly. If that helper does not yet exist in this file, you’ll need to:
1. Extract the common “is this sensitive?” logic from wherever the renderer does its filtering into a reusable function (e.g. `isSensitiveMockPath`).
2. Implement `cloneAndFilterMockTree` (or equivalent) to traverse the mock directory tree and apply `isSensitiveMockPath` based on `excludeSensitiveFiles`, and then import or define it in `scripts/capture-ui-screenshot.js`.
3. Ensure other mock usages (if any) also use this shared helper instead of their own inline filtering logic so behavior stays consistent.
</issue_to_address>

### Comment 2
<location> `tests/unit/file-analyzer.test.ts:409-416` </location>
<code_context>
       expect(result).toBeNull();
     });
+
+    test('should skip suspicious files when secret scanning is enabled', () => {
+      isBinaryFile.mockReturnValue(false);
+      fs.readFileSync.mockReturnValue(`const token = "${FAKE_GITHUB_TOKEN}";`);
+
+      const result = fileAnalyzer.analyzeFile('src/secrets.ts');
+
+      expect(result).toBeNull();
+      expect(mockTokenCounter.countTokens).not.toHaveBeenCalled();
+    });
   });
</code_context>

<issue_to_address>
**suggestion (testing):** Add tests for FileAnalyzer behavior when secret scanning is disabled

Please also add tests for the inverse cases: construct `FileAnalyzer` with (a) `enable_secret_scanning: false` and (b) `exclude_suspicious_files: false`, then assert that a file with the same token content is analyzed (i.e., `countTokens` is called and a non-null result is returned). This will complete coverage of the new configuration combinations.

Suggested implementation:

```typescript
    test('should skip suspicious files when secret scanning is enabled', () => {
      isBinaryFile.mockReturnValue(false);
      fs.readFileSync.mockReturnValue(`const token = "${FAKE_GITHUB_TOKEN}";`);

      const result = fileAnalyzer.analyzeFile('src/secrets.ts');

      expect(result).toBeNull();
      expect(mockTokenCounter.countTokens).not.toHaveBeenCalled();
    });

    test('should analyze suspicious files when secret scanning is disabled', () => {
      isBinaryFile.mockReturnValue(false);
      fs.readFileSync.mockReturnValue(`const token = "${FAKE_GITHUB_TOKEN}";`);

      const analyzer = new FileAnalyzer(mockTokenCounter, {
        enable_secret_scanning: false,
        exclude_suspicious_files: true,
      });

      const result = analyzer.analyzeFile('src/secrets.ts');

      expect(result).not.toBeNull();
      expect(mockTokenCounter.countTokens).toHaveBeenCalled();
    });

    test('should analyze suspicious files when excluding suspicious files is disabled', () => {
      isBinaryFile.mockReturnValue(false);
      fs.readFileSync.mockReturnValue(`const token = "${FAKE_GITHUB_TOKEN}";`);

      const analyzer = new FileAnalyzer(mockTokenCounter, {
        enable_secret_scanning: true,
        exclude_suspicious_files: false,
      });

      const result = analyzer.analyzeFile('src/secrets.ts');

      expect(result).not.toBeNull();
      expect(mockTokenCounter.countTokens).toHaveBeenCalled();
    });

```

1. Ensure that `mockTokenCounter` is defined in the test file scope (it likely already is, since it is used in the existing tests). If not, define it as a Jest mock and pass it into the default `fileAnalyzer` instance.
2. Confirm that the `FileAnalyzer` constructor signature matches `new FileAnalyzer(tokenCounter, options)`. If your implementation differs, adjust the `new FileAnalyzer(...)` calls accordingly.
3. If the configuration option names differ from `enable_secret_scanning` and `exclude_suspicious_files` in the implementation, update the option keys in the two new tests to match the actual configuration interface.
</issue_to_address>

### Comment 3
<location> `tests/unit/components/config-tab.test.tsx:74-75` </location>
<code_context>
     expect(screen.getByLabelText('Filter by file extensions')).toBeChecked();
     expect(screen.getByLabelText('Use exclude patterns')).toBeChecked();
     expect(screen.getByLabelText('Apply .gitignore rules')).toBeChecked();
+    expect(screen.getByLabelText('Scan content for secrets')).toBeChecked();
+    expect(screen.getByLabelText('Exclude suspicious files')).toBeChecked();

     // Check textareas
</code_context>

<issue_to_address>
**suggestion (testing):** Test that ConfigTab correctly persists secret-scanning toggles to the saved config

These assertions only cover the default UI state. Please add a test that toggles one or both checkboxes, triggers the save flow, and verifies the resulting config (via `onConfigChange` or YAML) reflects `enable_secret_scanning: false` / `exclude_suspicious_files: false` so we know the toggles actually persist into the saved config.

Suggested implementation:

```typescript
describe('ConfigTab', () => {
  it('persists secret scanning toggles into saved config', async () => {
    const onConfigChange = vi.fn(); // Use jest.fn() instead if the rest of the file uses Jest

    // Use the same render helper / props pattern as other tests in this file.
    // Example if existing tests do something like:
    // const { user } = renderConfigTab({ onConfigChange, initialConfig: getDefaultConfig() });
    const { user } = render(
      <ConfigTab
        // Spread whatever default/required props the other tests provide
        onConfigChange={onConfigChange}
      />,
    );

    // Secret scanning checkboxes should be checked by default
    const scanSecretsCheckbox = screen.getByLabelText('Scan content for secrets');
    const excludeSuspiciousCheckbox = screen.getByLabelText('Exclude suspicious files');
    expect(scanSecretsCheckbox).toBeChecked();
    expect(excludeSuspiciousCheckbox).toBeChecked();

    // Toggle them off
    await user.click(scanSecretsCheckbox);
    await user.click(excludeSuspiciousCheckbox);

    expect(scanSecretsCheckbox).not.toBeChecked();
    expect(excludeSuspiciousCheckbox).not.toBeChecked();

    // Trigger the same "save" flow used in other tests
    // (e.g. clicking a "Save" button or equivalent).
    const saveButton = screen.getByRole('button', { name: /save/i });
    await user.click(saveButton);

    // Assert that the saved config persists the toggled values.
    // If ConfigTab calls onConfigChange with a full config object:
    expect(onConfigChange).toHaveBeenCalled();
    const lastConfigArg = onConfigChange.mock.calls.at(-1)[0];

    expect(lastConfigArg).toMatchObject({
      enable_secret_scanning: false,
      exclude_suspicious_files: false,
    });

    // If instead the config is stored as YAML in a textarea, replace the above
    // with something like:
    //
    // const yamlTextarea = screen.getByLabelText(/configuration yaml/i);
    // expect(yamlTextarea).toHaveValue(
    //   expect.stringContaining('enable_secret_scanning: false'),
    // );
    // expect(yamlTextarea).toHaveValue(
    //   expect.stringContaining('exclude_suspicious_files: false'),
    // );
  });

```

To wire this up cleanly you’ll need to:

1. **Align the render call with existing tests**  
   - If the file already has a `renderConfigTab` or similar helper, replace the direct `render(<ConfigTab ... />)` call with that helper and pass `onConfigChange` through in the same way other tests do (including any `initialConfig` / `defaultConfig` props).

2. **Match the test framework**  
   - If the rest of the file uses Jest, replace `vi.fn()` with `jest.fn()` and `onConfigChange.mock.calls` access with the appropriate Jest mock typing if needed.

3. **Reuse the same "save" interaction used elsewhere**  
   - If other tests trigger persistence through a different element (e.g. a “Generate config” button, tab switch, or blur event), replace the `saveButton` click with that same interaction so you’re exercising the real save path.

4. **Use the same assertion style for config persistence**  
   - If other tests already assert against emitted config via `onConfigChange`, reuse that pattern (e.g. maybe they inspect the first call instead of the last).
   - If there is an existing YAML textarea that represents the saved config and other tests assert on its value, you can drop the `onConfigChange` assertions and instead assert that the YAML includes `enable_secret_scanning: false` and `exclude_suspicious_files: false`, using the same label/placeholder and matchers as the other tests.
</issue_to_address>

### Comment 4
<location> `tests/unit/utils/secret-scanner.test.ts:47-71` </location>
<code_context>
+    });
+  });
+
+  describe('scanContentForSecrets', () => {
+    test('should detect known secret patterns', () => {
+      const content = `
+        const token = "${FAKE_GITHUB_TOKEN}";
+        AWS_SECRET_ACCESS_KEY="${FAKE_AWS_SECRET_ACCESS_KEY}"
+      `;
+
+      const result = scanContentForSecrets(content);
+      expect(result.isSuspicious).toBe(true);
+      expect(result.matches.length).toBeGreaterThan(0);
+    });
+
+    test('should return clean result for normal content', () => {
+      const content = `
+        export const sum = (a, b) => a + b;
+        console.log("hello");
+      `;
+
+      const result = scanContentForSecrets(content);
+      expect(result).toEqual({
+        isSuspicious: false,
+        matches: [],
</code_context>

<issue_to_address>
**suggestion (testing):** Add targeted tests to cover all secret detection rules

The current tests only cover GitHub and AWS patterns. Please add small, rule-specific tests for the other patterns (Slack tokens, Stripe secret keys, JWT-like tokens, and the generic credential-assignment regex) so each rule is explicitly validated and future regex changes are caught by targeted failures.

```suggestion
  describe('scanContentForSecrets', () => {
    test('should detect known secret patterns', () => {
      const content = `
        const token = "${FAKE_GITHUB_TOKEN}";
        AWS_SECRET_ACCESS_KEY="${FAKE_AWS_SECRET_ACCESS_KEY}"
      `;

      const result = scanContentForSecrets(content);
      expect(result.isSuspicious).toBe(true);
      expect(result.matches.length).toBeGreaterThan(0);
    });

    test('should detect Slack tokens', () => {
      const content = `
        const slackToken = "xoxb-123456789012-1234567890123-abcdefghijklmnopqrstuvwx";
      `;

      const result = scanContentForSecrets(content);
      expect(result.isSuspicious).toBe(true);
      expect(result.matches.length).toBeGreaterThan(0);
    });

    test('should detect Stripe secret keys', () => {
      const content = `
        const stripeSecretKey = "sk_live_51H8aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRs";
      `;

      const result = scanContentForSecrets(content);
      expect(result.isSuspicious).toBe(true);
      expect(result.matches.length).toBeGreaterThan(0);
    });

    test('should detect JWT-like tokens', () => {
      const content = `
        const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
      `;

      const result = scanContentForSecrets(content);
      expect(result.isSuspicious).toBe(true);
      expect(result.matches.length).toBeGreaterThan(0);
    });

    test('should detect generic credential assignments', () => {
      const content = `
        const password = "super-secret-password";
        api_key = "abc123-very-secret-key";
      `;

      const result = scanContentForSecrets(content);
      expect(result.isSuspicious).toBe(true);
      expect(result.matches.length).toBeGreaterThan(0);
    });

    test('should return clean result for normal content', () => {
      const content = `
        export const sum = (a, b) => a + b;
        console.log("hello");
      `;

      const result = scanContentForSecrets(content);
      expect(result).toEqual({
        isSuspicious: false,
        matches: [],
      });
    });
  });
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread scripts/capture-ui-screenshot.js Outdated
Comment thread tests/unit/file-analyzer.test.ts
Comment thread tests/unit/components/config-tab.test.tsx
Comment thread tests/unit/utils/secret-scanner.test.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: be6b456e9e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/secret-scanner.ts Outdated
Comment on lines +75 to +79
const SENSITIVE_PATH_SEGMENTS = [
'/.aws/credentials',
'/.npmrc',
'/.pypirc',
'/.docker/config.json',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make sensitive-path detection work for relative paths

The new sensitive-path filter hard-codes segments with a leading /, but FileAnalyzer.shouldProcessFile calls shouldExclude with a relative path (see getRelativePath usage in src/main/index.ts). For repo-root files like .npmrc or .aws/credentials, the relative path is .npmrc/.aws/credentials and will never include /.npmrc or /.aws/credentials, so isSensitiveFilePath returns false and those files will be processed even with secret filtering enabled (and content scanning may miss unquoted tokens). This means secret filtering is ineffective for some sensitive dotfiles in the analysis path.

Useful? React with 👍 / 👎.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively strengthens the project's security posture by integrating gitleaks for staged secret scanning in pre-commit hooks and by adding secret filtering capabilities to the UI. The changes are well-implemented across the board, from the shell scripts to the React components and backend utilities. The addition of E2E tests for the new secret filtering behavior is a great way to ensure its correctness.

My main feedback is regarding some duplicated logic in the E2E test script (scripts/capture-ui-screenshot.js), where secret detection rules are reimplemented instead of being reused from the production code. Addressing this will improve maintainability and prevent the tests from becoming out of sync with the application's behavior.

Comment thread scripts/capture-ui-screenshot.js
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Feb 9, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Windows gitleaks path blocked 🐞 Bug ⛯ Reliability
Description
runGitleaksStaged() allows resolving gitleaks from ./bin, which on Windows produces an
  absolute path like C:\repo\bin\gitleaks.exe.
• The command validator rejects : and \ characters, so Windows absolute paths fail
  assertAllowedExecutable() and the new pre-commit gitleaks:staged hook can block commits unless
  gitleaks is already on PATH.
• This is now more user-impacting because .husky/pre-commit was changed to run `npm run
  gitleaks:staged` on every commit.
Code

scripts/lib/security.js[R178-188]

+async function runGitleaksStaged() {
+  const gitleaksPath = resolveCommand('gitleaks', [
+    path.join('bin', 'gitleaks'),
+    path.join('bin', 'gitleaks.exe'),
+  ]);
+
+  if (!gitleaksPath) {
+    throw new Error('gitleaks not found in PATH or ./bin (install gitleaks first)');
+  }
+  assertAllowedExecutable(gitleaksPath);
+
Evidence
resolveCommand returns an absolute path for local candidates. That absolute path is then passed to
assertAllowedExecutable(), which calls assertSafeCommand(). SAFE_COMMAND_PATTERN does not
allow : or \, which are present in typical Windows absolute paths. The pre-commit hook now
invokes this codepath.

scripts/lib/security.js[15-37]
scripts/lib/security.js[76-88]
scripts/lib/security.js[178-202]
.husky/pre-commit[1-9]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`resolveCommand()` can return an absolute Windows path for a repo-local executable (e.g., `C:\\...\\bin\\gitleaks.exe`). That path is passed into `assertSafeCommand()`, but `SAFE_COMMAND_PATTERN` rejects `:` and `\\`, causing `gitleaks:staged` (now run in pre-commit) to fail on Windows unless gitleaks is installed in PATH.
### Issue Context
- The code explicitly advertises `PATH or ./bin` support.
- Pre-commit now runs `npm run gitleaks:staged`, so this failure blocks commits.
### Fix Focus Areas
- scripts/lib/security.js[15-46]
- scripts/lib/security.js[76-91]
- scripts/lib/security.js[178-202]
- .husky/pre-commit[1-9]
### Suggested approach
1. Adjust `assertSafeCommand` (or introduce a separate validator) to allow:
- Windows drive letters and colons (e.g., `C:`) and backslashes for absolute paths.
- Still reject `..` segments.
2. Keep the allowlist check (`ALLOWED_EXECUTABLES`) based on `path.basename()`.
3. Consider normalizing `command` for validation only (e.g., replace `\\` with `/`) or using platform-specific regex:
- posix: current pattern OK
- win32: allow `[A-Za-z0-9._/\\:-]+` with additional checks to constrain `:` usage
4. Add a small unit/integration test for `resolveCommand` + `assertAllowedExecutable` on Windows-style paths (string-level test).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

✅ 2. Secret flags coupled 🐞 Bug ✓ Correctness
Description
• The UI exposes two separate options (“Scan content for secrets” and “Exclude suspicious files”),
  but the backend combines them with &&, making them functionally dependent.
• Result: turning either toggle off disables both sensitive-path exclusion and content scanning,
  which is unintuitive and can re-include sensitive files even when “Exclude suspicious files” is
  still checked.
• This affects both the file tree filtering (shouldExclude) and analysis-time skipping
  (FileAnalyzer.analyzeFile), so behavior will diverge from user intent.
Code

src/utils/secret-scanner.ts[R84-86]

+export const shouldExcludeSuspiciousFiles = (config?: ConfigObject): boolean =>
+  config?.enable_secret_scanning !== false && config?.exclude_suspicious_files !== false;
+
Evidence
ConfigTab presents two independent checkboxes, but shouldExcludeSuspiciousFiles requires both
config flags to be enabled, and both filtering and analysis paths are gated by this combined
function—so the toggles cannot operate independently.

src/renderer/components/ConfigTab.tsx[371-401]
src/utils/secret-scanner.ts[84-86]
src/utils/filter-utils.ts[65-90]
src/utils/file-analyzer.ts[124-142]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The UI provides two independent toggles for secret behavior, but the implementation currently combines them into a single boolean (`shouldExcludeSuspiciousFiles`) via `&amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;`. This prevents users from independently controlling scanning vs exclusion.
### Issue Context
- Path-based exclusion (`isSensitiveFilePath`) and content scanning (`scanContentForSecrets`) are different behaviors.
- The UI implies they’re independent.
### Fix Focus Areas
- src/utils/secret-scanner.ts[84-100]
- src/utils/filter-utils.ts[65-110]
- src/utils/file-analyzer.ts[124-148]
- src/renderer/components/ConfigTab.tsx[371-401]
### Suggested approach
1. Replace `shouldExcludeSuspiciousFiles` with two helpers, e.g.:
- `shouldScanForSecrets(config) =&amp;amp;amp;amp;gt; config?.enable_secret_scanning !== false`
- `shouldExcludeSensitiveFiles(config) =&amp;amp;amp;amp;gt; config?.exclude_suspicious_files !== false`
2. In `filter-utils`, gate `isSensitiveFilePath` exclusion only on `shouldExcludeSensitiveFiles`.
3. In `file-analyzer`, run `scanContentForSecrets` when `shouldScanForSecrets` is true, and only skip the file when suspicious **and** `shouldExcludeSensitiveFiles` is true.
4. Update/extend unit tests to cover the “scan on, exclude off” and “scan off, exclude on” combinations.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread scripts/lib/security.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/utils/secret-scanner.ts`:
- Around line 117-127: The current scanFileForSecrets function returns {
isSuspicious: false } on fs.readFileSync errors which allows files to bypass
scanning; change the error fallback to a fail-closed behavior by returning {
isSuspicious: true, matches: [], error: <error message> } or rethrowing the
error so callers must handle it; update scanFileForSecrets to include the caught
error details (or an error property) and/or make the behavior configurable
(e.g., a parameter or environment flag) while keeping the normal successful path
calling scanContentForSecrets(content).
🧹 Nitpick comments (9)
scripts/lib/security.js (1)

178-202: Consider extracting shared gitleaks resolution logic.

runGitleaksStaged duplicates the gitleaks resolution, validation, and spawn pattern from runGitleaks (lines 146–176). A small helper like resolveGitleaksOrThrow() returning { gitleaksPath, commandName, env } would eliminate this duplication across both functions.

♻️ Sketch of shared helper
+function resolveGitleaksOrThrow() {
+  const gitleaksPath = resolveCommand('gitleaks', [
+    path.join('bin', 'gitleaks'),
+    path.join('bin', 'gitleaks.exe'),
+  ]);
+  if (!gitleaksPath) {
+    throw new Error('gitleaks not found in PATH or ./bin (install gitleaks first)');
+  }
+  assertAllowedExecutable(gitleaksPath);
+  const commandName = process.platform === 'win32' ? 'gitleaks.exe' : 'gitleaks';
+  const env = withExecutablePath({ ...process.env }, gitleaksPath);
+  return { commandName, env };
+}
scripts/capture-ui-screenshot.js (1)

346-383: Duplicated sensitive-file detection logic inside addInitScript callback.

The inline isSensitive check (lines 360–366) duplicates isSensitiveMockPath (lines 268–281). This is unavoidable due to Playwright's addInitScript serialization boundary — functions from the outer scope can't be referenced inside the callback. Consider adding a brief comment explaining why, so future maintainers don't attempt to refactor one without updating the other.

📝 Suggested comment
+          // NOTE: This duplicates isSensitiveMockPath() because addInitScript
+          // serialises the callback — outer functions are not available here.
           const cloneAndFilter = (items) => {
.pre-commit-config.yaml (1)

34-37: Redundant gitleaks execution between Husky and pre-commit framework.

Both the Husky hook (invoking npm run gitleaks:staged) and the official gitleaks pre-commit hook (added here) scan staged changes using protect --staged. If both hook systems are active, gitleaks will scan staged files twice per commit.

Consider whether both systems are needed for gitleaks, or if one can serve as the sole enforcement gate.

src/utils/secret-scanner.ts (2)

66-80: Consider adding .env.local, .env.*.local, and common keyring/vault paths.

The sensitive file name patterns cover .env variants well, but you might also want to match paths like .ssh/ directory contents, *.tfvars (Terraform variables often contain secrets), and htpasswd files.


82-82: normalizeFilePath lowercases the entire path — may over-match on case-sensitive filesystems.

On Linux (case-sensitive FS), /Project/.Env and /project/.env are distinct paths. Lowercasing makes matching more aggressive, which is acceptable for a security filter (better to over-exclude than under-exclude), but worth noting in a comment for future maintainers.

tests/unit/components/config-tab.test.tsx (1)

20-21: New config options are mocked and asserted — good coverage of the render path.

Consider adding a toggle test for the new checkboxes (similar to the existing 'calls onConfigChange when checkbox changes' test for exclude patterns) to verify the debounced callback fires for secret-scanning toggles too. This can be deferred.

Also applies to: 74-75

tests/integration/main-process/handlers.test.ts (1)

330-354: Test relies on implicit default config for secret scanning — consider making it explicit.

The test works because shouldExcludeSuspiciousFiles returns true when config keys are undefined. However, the yaml.parse mock in beforeEach (line 158) returns a config without enable_secret_scanning / exclude_suspicious_files, so the test silently depends on this default. Adding the keys explicitly to the config would make the test's intent clearer and more resilient to future default changes.

Suggested improvement
       const configContent = `
         use_custom_excludes: true
         use_gitignore: true
         include_extensions:
           - .js
         exclude_patterns:
           - "**/node_modules/**"
+        enable_secret_scanning: true
+        exclude_suspicious_files: true
       `;
tests/unit/utils/secret-scanner.test.ts (1)

47-57: The AWS secret key pattern isn't tested in isolation.

The scanContentForSecrets test at lines 49-52 includes both FAKE_GITHUB_TOKEN and FAKE_AWS_SECRET_ACCESS_KEY in the same content string. If the AWS pattern doesn't actually match 'A'.repeat(40), the test still passes because the GitHub token triggers isSuspicious: true. Consider adding a separate test case with only the AWS key to ensure that pattern also matches independently.

Suggested addition
+    test('should detect AWS secret key pattern independently', () => {
+      const content = `AWS_SECRET_ACCESS_KEY="${FAKE_AWS_SECRET_ACCESS_KEY}"`;
+      const result = scanContentForSecrets(content);
+      expect(result.isSuspicious).toBe(true);
+      expect(result.matches.length).toBeGreaterThan(0);
+    });
src/renderer/components/ConfigTab.tsx (1)

77-83: The two flags are coupled in shouldExcludeSuspiciousFiles — consider a UI hint.

shouldExcludeSuspiciousFiles returns true only when both enable_secret_scanning and exclude_suspicious_files are not false. Unchecking "Scan content for secrets" also disables path-based file exclusion (.env, credentials, etc.), which users might not expect. A small helper text or disabling the "Exclude suspicious files" checkbox when scanning is off would clarify this dependency.

Comment thread src/utils/secret-scanner.ts
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