Skip to content

fix: restore vault sonar env and TS tailwind scan for QA screenshots#26

Merged
Mehdi-Bl merged 8 commits into
mainfrom
fix/tailwind-ts-content-scan
Feb 8, 2026
Merged

fix: restore vault sonar env and TS tailwind scan for QA screenshots#26
Mehdi-Bl merged 8 commits into
mainfrom
fix/tailwind-ts-content-scan

Conversation

@Mehdi-Bl

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

Copy link
Copy Markdown
Contributor

Summary

  • restore non-secret, committed Vault loader scaffolding for local Sonar workflows
  • restore robust Sonar environment loading (.env + .env.local) and fallback behavior
  • fix Tailwind content scanning for TypeScript/TSX so QA screenshots render styled UI
  • add secret scanning enforcement in local pre-commit and CI (Secrets Gate workflow)
  • remove updates/signing planning document from docs (kept as planning only)

Security Incident Handling

  • verified the leaked OAuth token from PR metadata history is revoked/invalid
  • resolved GitHub secret-scanning alert tied to that leaked token
  • confirmed repository source history did not contain hardcoded token strings

Validation

  • make sonar
  • npm run gitleaks
  • npm run lint
  • npm test -- --runInBand
  • npm run build:css && npm run build:webpack && npm run qa:screenshot

Summary by CodeRabbit

  • New Features

    • Vault-based secret loader and project environment presets
    • Native SonarQube scanner support and unauthenticated scan fallback
    • GitHub Secrets Gate workflow and local secret scan in pre-commit
  • Improvements

    • Multi-source environment loading and clearer env logging
    • Added TypeScript/TSX to Tailwind content scanning
    • Accessibility enhancements for tabs and controls
    • Dynamic UI mock generation for screenshot testing
  • Documentation

    • Removed outdated update/signing guide; added contributor agent guidelines and test catalog

@sourcery-ai

sourcery-ai Bot commented Feb 8, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR hardens and restores the Sonar/Vault environment loading and scanning pipeline by introducing a robust env loader and Vault helper script, preferring a native sonar-scanner when available, expanding Sonar configuration/env handling, and fixing Tailwind’s content configuration to include TypeScript/TSX so QA screenshots render correctly.

Sequence diagram for the updated SonarQube scan process

sequenceDiagram
  actor Developer
  participant NpmScript as Npm_script_sonar
  participant SonarScan as sonar_scan_js
  participant EnvLoader as Env_loader
  participant NativeScanner as Native_sonar_scanner
  participant NpmScanner as Npm_sonarqube_scanner
  participant SonarQube as SonarQube_server

  Developer->>NpmScript: Run npm_run_sonar
  NpmScript->>SonarScan: node scripts/sonar-scan.js

  Note over SonarScan,EnvLoader: Load Sonar and Vault related env vars
  SonarScan->>EnvLoader: Initialize_locked_env_keys
  EnvLoader->>EnvLoader: loadEnvViaBash(projectRoot, lockedEnvKeys)
  alt Env_vars_loaded_via_bash
    EnvLoader-->>SonarScan: bashLoadedKeys
  else No_env_from_bash
    EnvLoader->>EnvLoader: loadEnvFile(.env, lockedEnvKeys)
    EnvLoader-->>SonarScan: dotenv_keys
  end
  EnvLoader->>EnvLoader: loadEnvFile(.env.local, lockedEnvKeys)
  EnvLoader-->>SonarScan: local_dotenv_keys
  SonarScan->>SonarScan: Resolve sonarUrl and sonarToken
  SonarScan->>SonarScan: Read sonar-project.properties
  SonarScan->>SonarScan: Resolve projectKey, projectName, projectVersion

  SonarScan->>SonarScan: Build scannerOptions
  alt sonarToken_present
    SonarScan->>SonarScan: Add sonar.token to scannerOptions
  else sonarToken_missing
    SonarScan->>Developer: Log_unauthenticated_scan_message
  end

  Note over SonarScan,NativeScanner: Prefer native sonar-scanner if available
  SonarScan->>NativeScanner: runWithNativeScanner(scannerOptions)
  alt Native_scanner_found_and_successful
    NativeScanner->>SonarQube: Execute_scan_with_properties
    SonarQube-->>NativeScanner: Analysis_success
    NativeScanner-->>SonarScan: success
    SonarScan->>Developer: Log_scan_completed_successfully
  else Native_scanner_not_found
    SonarScan->>SonarScan: Log_native_scanner_not_found
    SonarScan->>NpmScanner: sonarqubeScanner(scannerConfig, callback)
    NpmScanner->>SonarQube: Execute_scan_via_wrapper
    SonarQube-->>NpmScanner: Analysis_result
    alt Wrapper_scan_success
      NpmScanner-->>SonarScan: null_error
      SonarScan->>Developer: Log_scan_completed_successfully
    else Wrapper_scan_failure
      NpmScanner-->>SonarScan: error_object
      SonarScan->>Developer: Log_failure_and_auth_hints
    end
  end
Loading

Flow diagram for vault_helper.sh secret loading

graph TD
  Start["Start_vault_helper_load_from_definitions"] --> CheckDefs["Check_VAULT_SECRET_PATHS_present"]
  CheckDefs -->|No| ErrorNoDefs["Log_error_no_secret_paths_and_exit"]
  CheckDefs -->|Yes| ParseDefs["Parse_secret_definitions_and_required_vars"]

  ParseDefs --> RequireCli["Require_vault_and_jq_binaries"]
  RequireCli -->|Missing_cli| ErrorCli["Log_error_missing_cli_and_exit"]
  RequireCli -->|OK| LoadToken["Try_load_VAULT_TOKEN_from_VAULT_TOKEN_FILE"]

  LoadToken --> ValidateToken["Validate_existing_or_loaded_token"]
  ValidateToken -->|Valid| HaveToken["Use_existing_valid_token"]
  ValidateToken -->|Invalid| AuthFlow["Prompt_user_and_authenticate_with_vault"]
  AuthFlow -->|Failure| ErrorAuth["Log_authentication_failure_and_exit"]
  AuthFlow -->|Success| HaveToken

  HaveToken --> LoopPaths["For_each_secret_definition"]

  LoopPaths --> ParseEntry["Parse_entry_into_path_and_optional_mappings"]
  ParseEntry -->|Empty_path| WarnSkip["Log_warning_and_skip_entry"]
  ParseEntry -->|Valid_path| FetchSecrets["vault_kv_get_JSON_for_path"]

  FetchSecrets -->|Failure| ErrorFetch["Log_error_fetching_secrets_and_exit"]
  FetchSecrets -->|Success| ExtractData["Extract_data_object_from_JSON"]
  ExtractData -->|Empty_data| WarnNoSecrets["Log_warning_no_secrets_and_continue"]
  ExtractData -->|Has_data| ExportEnv["Generate_export_statements_and_eval"]

  ExportEnv --> ApplyMappings["Apply_optional_VAR_to_key_mappings"]
  ApplyMappings --> NextPath["Next_secret_definition"]
  WarnNoSecrets --> NextPath
  WarnSkip --> NextPath
  NextPath -->|More_paths| LoopPaths
  NextPath -->|No_more_paths| CheckRequired["Validate_required_env_vars_if_any"]

  CheckRequired -->|Missing_required| ErrorMissing["Log_missing_required_vars_and_exit"]
  CheckRequired -->|All_present| Success["Log_success_Vault_secrets_loaded"]

  ErrorNoDefs --> End["Exit_with_failure"]
  ErrorCli --> End
  ErrorAuth --> End
  ErrorFetch --> End
  ErrorMissing --> End
  Success --> End
Loading

File-Level Changes

Change Details Files
Replace naive .env loader in sonar-scan.js with a robust loader that merges .env/.env.local/.env.vault while respecting existing process env and focusing on Sonar/Vault/DTrack variables.
  • Introduce helpers to parse env values (quoted, escaped, and with trailing comments) and prefer or ignore overrides based on a locked set of initial process.env keys.
  • Load env values via a Bash subprocess that sources .env.vault and .env, falls back to direct .env/.env.local parsing, and restricts imported variables from the shell to SONAR_, VAULT_, DTRACK_* and DTR_PROJECT_KEY.
  • Adjust SONAR_URL resolution to also consider SONAR_HOST_URL and default to http://localhost:9000, while allowing scans to proceed without SONAR_TOKEN (unauthenticated).
scripts/sonar-scan.js
Enhance sonar-scan.js to prefer a native sonar-scanner binary when available and fall back to the npm sonarqube-scanner wrapper, with richer configuration derived from env and sonar-project.properties.
  • Add resolution logic for a native sonar-scanner via SONAR_SCANNER_PATH, system PATH (which/where), or ~/.sonar/sonar-scanner-* directories, avoiding the npm .bin wrapper.
  • Wrap native scanner execution with spawnSync, building -D sonar.* arguments from merged properties and env (including project key/name/version, sources, tests, exclusions, coverage, encoding, server URL, and token).
  • Improve sonar-project.properties parsing to handle lines containing '=' in the value, and expand project key/name/version resolution to accept SONAR_PROJECT, SONAR_PROJECT_NAME, and SONAR_PROJECT_VERSION env vars.
scripts/sonar-scan.js
Add a reusable Bash vault-helper script to securely fetch, map, and validate secrets from Vault into the environment for local tooling.
  • Implement logging, CLI presence checks (vault, jq), token trimming and persistence (~/.vault-token by default), and token validation via vault token lookup.
  • Provide interactive Vault authentication via userpass method, storing a validated client token and exporting VAULT_TOKEN.
  • Support loading secrets from one or more VAULT_SECRET_PATHS definitions with optional key-to-env mappings, exporting all kv values, applying mappings, and enforcing required env vars specified in VAULT_REQUIRED_VARS.
scripts/vault-helper.sh
Fix Tailwind CSS content scanning to include TypeScript and TSX files so styled components appear correctly in QA screenshots.
  • Extend Tailwind content globs to cover .ts and .tsx files under src/renderer in addition to existing JS/JSX and index.html.
  • This ensures Tailwind picks up class names used in the TypeScript React code so production/QA builds render with proper styles.
tailwind.config.js
Commit non-secret configuration artifacts to support the restored Vault and Sonar setup.
  • Stop ignoring the local Vault loader script so vault-helper.sh remains versioned (gitignore change, not fully shown).
  • Introduce a tracked .env file (expected to hold non-secret or template values) to anchor the env-loading workflow used by sonar-scan.js and Vault integration.
.gitignore
.env

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 8, 2026

Copy link
Copy Markdown

Dependency Review

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

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/checkout de0fac2e4500dabe0009e67214ff5f5447ce83dd 🟢 6.4
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 57 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection🟢 6branch protection is not maximal on development and all release branches
Vulnerabilities🟢 73 existing vulnerabilities detected
SAST🟢 8SAST tool detected but not run on all commits
actions/actions/upload-artifact b7c566a772e6b6bfb58ed0dc250532a479d7789f 🟢 6.2
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Code-Review🟢 10all changesets reviewed
Maintained🟢 1027 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Vulnerabilities🟢 64 existing vulnerabilities detected
SAST🟢 10SAST tool is run on all commits

Scanned Files

  • .github/workflows/secrets-gate.yml

@coderabbitai

coderabbitai Bot commented Feb 8, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a tracked shell environment loader (.env) and Vault loader; introduces a Bash vault helper for token/auth and secret export; refactors SonarQube scan to merge env sources and try a native scanner; adds gitleaks CI/workflow and pre-commit check; expands UI screenshot mocks and TypeScript typings; small build and docs updates.

Changes

Cohort / File(s) Summary
Environment loader & gitignore
\.env, \.gitignore
Adds a shell-based .env loader that sources Vault definitions, resolves VAULT_TOKEN/VAULT_TOKEN_FILE fallbacks, and predefines Sonar/Dependency-Track variables; removes .env from .gitignore so .env is tracked.
Vault integration
scripts/vault-helper.sh
New Bash vault helper implementing CLI checks, token discovery/persistence, interactive auth, secret fetch/parsing, env export and mappings, and required-var validation; exposes vault_helper::load_from_definitions entrypoint.
SonarQube scanner
scripts/sonar-scan.js
Reworked environment loading (shell exports + .env/.env.local parsing), logging/redaction, native sonar-scanner resolution & execution (PATH & ~/.sonar lookup with Windows handling) with fallback to npm wrapper, dynamic scannerOptions construction, and conditional unauthenticated runs.
Secrets scanning / pre-commit
.github/workflows/secrets-gate.yml, .husky/pre-commit
Adds "Secrets Gate" GitHub Action using gitleaks (JSON artifact upload) and updates pre-commit to run gitleaks (fail commits on detected secrets).
UI screenshot & test scaffolding
scripts/capture-ui-screenshot.js, tests/catalog.md
Replaces static mock tree with programmatic mock repo generator, expands UI interactions to traverse deep trees and validate multi-file selection before screenshot; adds tests catalog documentation.
Type additions & renderer updates
src/types/ipc.ts, src/types/global.d.ts, src/renderer/components/...
Adds exported types TabId and SelectionHandler and propagates them into renderer components (App, TabBar, FileTree, SourceTab), plus small accessibility and error-handling UI tweaks.
Build config & styles
tailwind.config.js
Expanded Tailwind content globs to include .ts and .tsx files.
Docs & housekeeping
docs/DEVELOPMENT.md, docs/UPDATES_AND_SIGNING.md, AGENTS.md
Deletes docs/UPDATES_AND_SIGNING.md, removes a reference in DEVELOPMENT.md, and adds AGENTS.md contributor guidance.
CI automation
.github/dependabot.yml
Adds Dependabot config for weekly npm and GitHub Actions updates.
Misc small changes
scripts/sonar-scan.js (other internal additions), scripts/vault-helper.sh, scripts/capture-ui-screenshot.js
Multiple internal additions and helper functions across scripts; sonar-scan.js introduces many parsing/util functions and native-run helpers.

Sequence Diagram(s)

sequenceDiagram
    actor Dev
    participant Env as .env Loader
    participant VaultHelper as vault-helper.sh
    participant Vault as Vault Service
    participant Scanner as sonar-scan.js
    participant Native as Native Scanner

    Dev->>Env: source .env
    Env->>VaultHelper: vault_helper::load_from_definitions(defs, required, token_file)
    VaultHelper->>VaultHelper: discover/validate VAULT_TOKEN (env/file)
    alt token missing
        VaultHelper->>Dev: prompt for credentials
        Dev->>VaultHelper: provide credentials
        VaultHelper->>Vault: authenticate -> token
        Vault->>VaultHelper: return token
        VaultHelper->>VaultHelper: save token (file)
    end
    VaultHelper->>Vault: fetch secret paths
    Vault->>VaultHelper: return secret payloads
    VaultHelper->>Env: export secrets as env vars
    Env->>Scanner: invoke sonar-scan.js (with env)
    Scanner->>Scanner: merge env from shell/.env/.env.local
    Scanner->>Native: resolveNativeScannerPath()
    alt native found
        Scanner->>Native: run native scanner with -D options
        Native->>Scanner: exit status
    else
        Scanner->>Scanner: fallback to npm wrapper scanner
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰
I hopped through scripts at break of day,
Found secrets snug where tokens lay,
I sourced the .env and fetched the key,
Sonar hummed while scanners ran free,
Tailwind twitched—tests smiled, hip-hip-hooray!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.94% 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 PR title clearly and accurately summarizes the primary changes: restoring Vault/Sonar environment setup and fixing Tailwind's TypeScript/TSX content scanning. It is concise and specific.

✏️ 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 fix/tailwind-ts-content-scan

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

Restore vault-backed sonar env and tailwind TS scanning

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Refactored environment variable loading with vault support and bash sourcing
  - Added loadEnvViaBash() to source .env.vault and .env files via bash
  - Implemented parseEnvValue() for proper quote and escape sequence handling
  - Added selective environment variable loading based on variable type (SONAR_, VAULT_, DTRACK_)
• Implemented native sonar-scanner detection and execution
  - Added runWithNativeScanner() to use native binary instead of npm wrapper
  - Added resolveNativeScannerPath() to locate scanner in PATH or ~/.sonar directory
  - Falls back to npm wrapper if native scanner unavailable
• Extended Tailwind CSS content scanning to include TypeScript files
  - Updated content pattern to include .ts and .tsx extensions
• Created vault-helper.sh bash utility for secure secret management
  - Provides token validation, authentication, and secret fetching from Vault
  - Supports custom variable mappings and required variable validation
• Restored committed .env file with vault loader wrapper
  - Loads SonarQube and DependencyTrack secrets from Vault
  - Provides sensible defaults for local development
Diagram
flowchart LR
  A["sonar-scan.js"] -->|loads via bash| B["loadEnvViaBash()"]
  B -->|sources| C[".env.vault & .env"]
  C -->|provides tokens| D["SONAR_TOKEN<br/>DTRACK_API_KEY"]
  A -->|attempts| E["runWithNativeScanner()"]
  E -->|resolves path| F["resolveNativeScannerPath()"]
  F -->|finds binary| G["~/.sonar/sonar-scanner"]
  E -->|fallback| H["npm sonarqube-scanner"]
  A -->|scans| I["src/renderer/**/*.{js,jsx,ts,tsx}"]
  J[".env"] -->|sources| K["vault-helper.sh"]
  K -->|authenticates| L["Vault"]
  L -->|returns secrets| M["kv/Sonarqube<br/>kv/dependencytrack"]
Loading

Grey Divider

File Changes

1. scripts/sonar-scan.js ✨ Enhancement +308/-73

Refactor env loading and add native scanner support

• Refactored environment loading to support bash sourcing of .env.vault and .env files with
 proper quote/escape handling
• Added native sonar-scanner detection and execution with fallback to npm wrapper
• Implemented selective environment variable loading for SONAR_, VAULT_, and DTRACK_ prefixed
 variables
• Enhanced scanner options to support optional SONAR_TOKEN and added sonar.host.url configuration
• Improved properties file parsing to handle edge cases with delimiter positioning
• Added support for SONAR_PROJECT and SONAR_PROJECT_NAME environment variables

scripts/sonar-scan.js


2. tailwind.config.js ✨ Enhancement +1/-1

Add TypeScript file scanning to Tailwind

• Extended content pattern to include TypeScript file extensions (.ts, .tsx)
• Enables Tailwind CSS scanning of TypeScript source files in addition to JavaScript

tailwind.config.js


3. scripts/vault-helper.sh ✨ Enhancement +250/-0

Add vault helper bash utility script

• New bash utility script providing comprehensive Vault integration functions
• Implements token management (load, save, validate), authentication, and secret fetching
• Supports custom variable mappings and required variable validation
• Includes logging functions and error handling for Vault operations

scripts/vault-helper.sh


View more (1)
4. .env ⚙️ Configuration changes +58/-0

Add vault-backed environment loader wrapper

• New committed .env file containing vault loader wrapper script
• Sources vault-helper.sh to load secrets from Vault for SonarQube and DependencyTrack
• Provides default vault paths and required variables configuration
• Sets local development defaults for DTRACK_PROJECT and SONAR_PROJECT_KEY

.env


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 enhances the project's development and CI/CD environment by re-establishing a robust system for managing environment variables and secrets via Vault, improving the SonarQube scanning process, and ensuring correct styling for UI components. The changes streamline the setup for local development and automated quality checks, while also addressing a security alert.

Highlights

  • Vault Environment Loader Restoration: Reintroduced a non-secret Vault environment loader, enabling robust loading of SonarQube and Dependency-Track related environment variables.
  • .env File Versioning: Modified .gitignore to allow the .env file (containing non-secret configurations) to be committed, ensuring the local Vault loader remains versioned.
  • Enhanced SonarQube Scan Script: Significantly refactored the sonar-scan.js script to support loading environment variables from multiple sources (.env.vault, .env, .env.local), prioritize specific variables, and dynamically use either a native sonar-scanner or the npm wrapper.
  • Tailwind CSS TypeScript Scanning Fix: Updated tailwind.config.js to include TypeScript files (.ts, .tsx) in its content scanning, resolving issues with styled UI rendering in QA screenshots.
  • Security Incident Resolution: Addressed and resolved a GitHub secret-scanning alert, confirming it was a false positive related to PR body history.

🧠 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
  • .env
    • Added a new file to serve as a Vault environment loader wrapper.
    • Includes logic to source vault-helper.sh and define default secret paths and required variables for SonarQube and Dependency-Track.
    • Manages VAULT_TOKEN_FILE discovery and export.
  • .gitignore
    • Removed .env from the ignore list, allowing it to be tracked by Git.
  • scripts/sonar-scan.js
    • Implemented new functions (parseEnvValue, shouldPreferDotenvValue, shouldImportFromShell, loadEnvFile, loadEnvViaBash) for more flexible and prioritized environment variable loading from .env.vault, .env, and .env.local.
    • Introduced runWithNativeScanner, resolveNativeScannerPath, and isNpmScannerWrapperPath to detect and utilize a native sonar-scanner installation, falling back to the npm package if not found.
    • Updated sonar-project.properties parsing to handle key-value pairs more accurately, including multi-line values.
    • Adjusted project key, name, and version resolution to consider SONAR_PROJECT and SONAR_PROJECT_NAME environment variables.
    • Added a console log for unauthenticated scans when SONAR_TOKEN is missing.
  • scripts/vault-helper.sh
    • Added a new shell script containing helper functions for Vault interaction.
    • Includes functions for logging (log_info, log_warn, log_error), CLI tool validation (require_cli), string manipulation (trim_token, trim_string), token management (load_token_from_file, save_token, validate_token), user authentication (authenticate), secret mapping (set_secret_if_empty, apply_mappings), secret fetching (fetch_and_export), and validation of required variables (validate_required_vars).
    • Provides the core logic for vault_helper::load_from_definitions to process secret paths and load environment variables.
  • tailwind.config.js
    • Modified the content array to include **/.ts and **/.tsx files, ensuring Tailwind CSS correctly scans TypeScript components for utility classes.
Activity
  • The pull request includes extensive validation output from various npm scripts, demonstrating thorough testing of the changes. This includes sonar (SonarQube scan), gitleaks (secret scanning), lint (ESLint), test (Jest), build:css (Tailwind CSS build), build:webpack (Webpack build), and qa:screenshot (UI screenshot capture).
  • The author also explicitly mentioned handling a GitHub secret-scanning alert, verifying it was a false positive and resolving it, indicating attention to security concerns.
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 2 issues, and left some high level feedback:

  • sonar-scan.js has grown quite large and multi-purpose (env loading, scanner resolution, execution); consider extracting the env-loading helpers and native-scanner resolution into separate modules to keep the script easier to reason about and maintain.
  • vault-helper.sh’s authenticate flow is fully interactive (read username/password from tty), which makes it hard to use in CI or non-interactive environments; consider supporting non-interactive login via environment variables or existing Vault auth methods as a fallback.
  • The SONAR_/VAULT_/DTRACK_ prefix logic in shouldPreferDotenvValue/shouldImportFromShell hardcodes which keys are overridden/imported; consider centralizing these prefixes in a single configuration structure so it’s clear and easier to extend if additional key families are needed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- sonar-scan.js has grown quite large and multi-purpose (env loading, scanner resolution, execution); consider extracting the env-loading helpers and native-scanner resolution into separate modules to keep the script easier to reason about and maintain.
- vault-helper.sh’s authenticate flow is fully interactive (read username/password from tty), which makes it hard to use in CI or non-interactive environments; consider supporting non-interactive login via environment variables or existing Vault auth methods as a fallback.
- The SONAR_/VAULT_/DTRACK_ prefix logic in shouldPreferDotenvValue/shouldImportFromShell hardcodes which keys are overridden/imported; consider centralizing these prefixes in a single configuration structure so it’s clear and easier to extend if additional key families are needed.

## Individual Comments

### Comment 1
<location> `scripts/vault-helper.sh:44` </location>
<code_context>
+    local token="$1"
+    local file="$2"
+    mkdir -p "$(dirname "$file")"
+    umask 077
+    printf '%s\n' "$token" >"$file"
+    chmod 600 "$file" 2>/dev/null || true
</code_context>

<issue_to_address>
**issue (bug_risk):** Changing umask in save_token has a global side effect on the caller shell.

`umask 077` here permanently changes the process umask, which can unexpectedly alter permissions of files created later by callers sourcing this helper. Consider saving and restoring the previous umask, for example:

```bash
vault_helper::save_token() {
    local token="$1" file="$2" old_umask
    old_umask=$(umask)
    mkdir -p "$(dirname "$file")"
    umask 077
    printf '%s
' "$token" >"$file"
    umask "$old_umask"
    chmod 600 "$file" 2>/dev/null || true
    vault_helper::log_info "Saved Vault token to $file"
}
```
</issue_to_address>

### Comment 2
<location> `scripts/vault-helper.sh:78-84` </location>
<code_context>
+
+    VAULT_TOKEN="$token"
+    export VAULT_TOKEN
+    vault_helper::save_token "$token" "$VAULT_TOKEN_FILE"
+
+    unset username password token
</code_context>

<issue_to_address>
**suggestion (bug_risk):** authenticate assumes VAULT_TOKEN_FILE is set, which may break if used outside load_from_definitions.

Here `vault_helper::authenticate` passes `$VAULT_TOKEN_FILE` to `vault_helper::save_token`, but that variable is only set in `vault_helper::load_from_definitions`. If `authenticate` is called directly (e.g. from another script), `$VAULT_TOKEN_FILE` may be empty and the token may be written to an unintended or invalid path. Consider defaulting to `$HOME/.vault-token` when it’s unset, or failing fast with a clear error instead.

```suggestion
    VAULT_TOKEN="$token"
    export VAULT_TOKEN

    # Determine where to save the Vault token:
    # - Prefer explicitly configured VAULT_TOKEN_FILE
    # - Fallback to the standard ~/.vault-token location
    local token_file="${VAULT_TOKEN_FILE:-${HOME:+$HOME/.vault-token}}"

    if [[ -z "$token_file" ]]; then
        vault_helper::log_error "VAULT_TOKEN_FILE is not set and HOME is unset; cannot determine token file path"
        unset username password token
        return 1
    fi

    vault_helper::save_token "$token" "$token_file"

    unset username password token
    return 0
}
```
</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/vault-helper.sh
local token="$1"
local file="$2"
mkdir -p "$(dirname "$file")"
umask 077

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Changing umask in save_token has a global side effect on the caller shell.

umask 077 here permanently changes the process umask, which can unexpectedly alter permissions of files created later by callers sourcing this helper. Consider saving and restoring the previous umask, for example:

vault_helper::save_token() {
    local token="$1" file="$2" old_umask
    old_umask=$(umask)
    mkdir -p "$(dirname "$file")"
    umask 077
    printf '%s
' "$token" >"$file"
    umask "$old_umask"
    chmod 600 "$file" 2>/dev/null || true
    vault_helper::log_info "Saved Vault token to $file"
}

Comment thread scripts/vault-helper.sh
Comment on lines +78 to +84
VAULT_TOKEN="$token"
export VAULT_TOKEN
vault_helper::save_token "$token" "$VAULT_TOKEN_FILE"

unset username password token
return 0
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): authenticate assumes VAULT_TOKEN_FILE is set, which may break if used outside load_from_definitions.

Here vault_helper::authenticate passes $VAULT_TOKEN_FILE to vault_helper::save_token, but that variable is only set in vault_helper::load_from_definitions. If authenticate is called directly (e.g. from another script), $VAULT_TOKEN_FILE may be empty and the token may be written to an unintended or invalid path. Consider defaulting to $HOME/.vault-token when it’s unset, or failing fast with a clear error instead.

Suggested change
VAULT_TOKEN="$token"
export VAULT_TOKEN
vault_helper::save_token "$token" "$VAULT_TOKEN_FILE"
unset username password token
return 0
}
VAULT_TOKEN="$token"
export VAULT_TOKEN
# Determine where to save the Vault token:
# - Prefer explicitly configured VAULT_TOKEN_FILE
# - Fallback to the standard ~/.vault-token location
local token_file="${VAULT_TOKEN_FILE:-${HOME:+$HOME/.vault-token}}"
if [[ -z "$token_file" ]]; then
vault_helper::log_error "VAULT_TOKEN_FILE is not set and HOME is unset; cannot determine token file path"
unset username password token
return 1
fi
vault_helper::save_token "$token" "$token_file"
unset username password token
return 0
}

@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 aims to enhance the development and CI workflow by improving the SonarQube scanning script, adding a vault-helper.sh for secret management, and fixing the Tailwind CSS configuration. However, it introduces several critical security vulnerabilities, primarily Remote Code Execution (RCE) in scripts/sonar-scan.js due to sourcing environment files as bash scripts. Further command injection risks exist with shell: true on Windows and eval in the Vault helper script. While the changes are well-implemented and include positive enhancements like prioritizing a native sonar-scanner binary, there are minor suggestions to improve script robustness. It is highly recommended to address these security concerns by using safe environment variable parsers and avoiding the execution of untrusted content as shell scripts.

Comment thread scripts/sonar-scan.js
Comment on lines +109 to +114
const result = spawnSync('bash', ['-lc', shellScript], {
cwd: projectRoot,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'inherit'],
env: process.env,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-critical critical

The loadEnvViaBash function executes spawnSync('bash', ['-lc', shellScript], ...) where shellScript sources ./.env and ./.env.vault. This creates a critical Remote Code Execution (RCE) vulnerability, as an attacker can modify .env in a pull request to execute malicious bash code on the CI server or a developer's machine when the sonar scan runs. Additionally, the -l (login) flag in bash -lc can introduce unpredictable environment variables from user-specific profile scripts, making the script less consistent. It is recommended to address the RCE by using safe environment variable parsers and avoiding the execution of untrusted content as shell scripts, and to remove the -l flag for more isolated and secure execution.

Comment thread scripts/sonar-scan.js
Comment thread scripts/vault-helper.sh
return 1
fi

eval "$exports"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-medium medium

The script uses eval to export environment variables fetched from Vault. While the values are escaped using jq's @sh filter, the keys are not. If an attacker can control the keys of the secrets stored in Vault, they can inject arbitrary shell commands that will be executed when eval "$exports" is called. For example, a secret key named VAR; touch /tmp/pwned would result in the execution of touch /tmp/pwned.

Comment thread scripts/vault-helper.sh
read -r -s -p "Vault password: " password
echo >&2

if ! login_json=$(vault login -format=json -method=userpass username="$username" password="$password" 2>/dev/null); then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In the vault_helper::authenticate function, stderr from the vault login command is redirected to /dev/null. This suppresses potentially useful error messages if authentication fails, making it difficult to debug issues related to incorrect credentials, network problems, or a misconfigured Vault address. By removing the redirection, Vault's native error messages will be displayed, improving debuggability.

Suggested change
if ! login_json=$(vault login -format=json -method=userpass username="$username" password="$password" 2>/dev/null); then
if ! login_json=$(vault login -format=json -method=userpass username="$username" password="$password"); then

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/sonar-scan.js (1)

279-281: ⚠️ Potential issue | 🟡 Minor

sonar-project.properties read will throw if file is missing.

fs.readFileSync on line 281 throws an uncaught exception if the file doesn't exist, crashing the script with an opaque error. Other file accesses in this script (coverage path, .env) use existsSync guards.

🛡️ Proposed fix
 const propertiesPath = path.join(__dirname, '..', 'sonar-project.properties');
-const propertiesContent = fs.readFileSync(propertiesPath, 'utf8');
 const properties = {};
+if (fs.existsSync(propertiesPath)) {
+  const propertiesContent = fs.readFileSync(propertiesPath, 'utf8');

-// Simple parser for properties file
-propertiesContent.split('\n').forEach((line) => {
-  line = line.trim();
-  if (line && !line.startsWith('#')) {
-    const delimiterIndex = line.indexOf('=');
-    if (delimiterIndex === -1) {
-      return;
-    }
-    const key = line.slice(0, delimiterIndex).trim();
-    const value = line.slice(delimiterIndex + 1).trim();
-    if (key && value) {
-      properties[key] = value;
+  propertiesContent.split('\n').forEach((line) => {
+    line = line.trim();
+    if (line && !line.startsWith('#')) {
+      const delimiterIndex = line.indexOf('=');
+      if (delimiterIndex === -1) {
+        return;
+      }
+      const key = line.slice(0, delimiterIndex).trim();
+      const value = line.slice(delimiterIndex + 1).trim();
+      if (key && value) {
+        properties[key] = value;
+      }
     }
-  }
-});
+  });
+}
🤖 Fix all issues with AI agents
In `@scripts/sonar-scan.js`:
- Around line 301-305: The default Sonar project key fallback is stale: update
the fallback value used when resolving projectKey (the expression assigning to
projectKey that checks process.env.SONAR_PROJECT_KEY, process.env.SONAR_PROJECT,
and properties['sonar.projectKey']) to use 'ai-code-fusion' instead of
'ai-code-prep' so the code, .env, and Sonar logs are consistent.
- Around line 92-147: The spawned bash in loadEnvViaBash is getting log lines
from vault-helper.sh on stdout which corrupt env -0 output; fix this by changing
vault-helper.sh's log_info and log_warn to write to stderr (use >&2 or redirect
their prints to stderr) so they no longer pollute stdout, and also make
loadEnvViaBash more robust by sanitizing result.stdout before parsing (e.g.,
drop any leading bytes up to the first NUL or filter out lines/entries that
don't look like valid KEY=VALUE pairs) in the loadEnvViaBash function so stray
helper output can't inject malformed entries.

In `@scripts/vault-helper.sh`:
- Around line 59-84: In vault_helper::authenticate change the vault login
invocation so the password is not passed as a CLI argument (avoid
password="$password"); instead omit the password arg and feed the password via
stdin (e.g. pipe printf '%s\n' "$password" into the vault login command or let
vault prompt for the password) so the secret never appears in the process list;
update the login_json assignment that currently calls vault login -format=json
-method=userpass username="$username" password="$password" to the stdin-based
variant and keep the rest of the function (token extraction, VAULT_TOKEN export,
vault_helper::save_token) unchanged.
- Around line 40-48: The vault_helper::save_token function sets umask 077
globally which leaks into the caller's shell; change the implementation to scope
the umask to the write operation only (e.g., run the mkdir/printf/chmod sequence
inside a subshell or use a grouped command with a locally-set umask) so the
restrictive umask does not persist after the function returns, and keep the
vault_helper::log_info call outside or after the subshell as needed.
- Around line 141-149: The current use of eval "$exports" after building export
lines from data_json is a command-injection risk because the jq template embeds
.key unescaped; change this to either (a) escape keys with `@sh` in the jq output
so both key and value are safely quoted before eval, or (b) eliminate eval
entirely by iterating over keys parsed from data_json (e.g., using jq -r
'keys[]' or to_entries[]), and for each key use a safe assignment pattern like
printf -v / export (the same approach used by set_secret_if_empty) to set
environment variables; ensure you update the error path that calls
vault_helper::log_error when parsing fails and keep the behavior of returning 1
on error.
🧹 Nitpick comments (4)
scripts/vault-helper.sh (1)

86-96: Shellcheck SC2163 is a false positive here, but consider a clearer idiom.

export "$var" where $var holds a variable name like SONAR_TOKEN is correct and intentional — it marks the already-assigned variable for export. ShellCheck flags it because it can't infer intent. You can silence it with a directive, or use the combined declare -gx idiom:

♻️ Optional: silence SC2163
 vault_helper::set_secret_if_empty() {
     local var="$1"
     local value="$2"
     local source="$3"

     if [[ -z "${!var:-}" && -n "$value" ]]; then
         printf -v "$var" '%s' "$value"
+        # shellcheck disable=SC2163
         export "$var"
         vault_helper::log_info "Mapped ${source} -> ${var}"
     fi
 }
.env (2)

1-3: Shebang on line 3 is ineffective; line 1 comment has a grammar nit.

The shebang (#!/usr/bin/env bash) must be the very first line of the file to be recognized by the kernel. Since this file is always sourced (never executed directly), it's cosmetic — but it's misleading where it sits. Also, line 1 reads like it's missing punctuation: "This file is committed to git no secrets" → "committed to git — no secrets."

♻️ Suggested reorder
-# This file is committed to git no secrets.
-
-#!/usr/bin/env bash
+#!/usr/bin/env bash
+# This file is committed to git — no secrets.

1-58: All dotenv-linter warnings are false positives — this is a bash script, not a dotenv file.

The .env filename causes dotenv-linter to parse this as a KEY=VALUE file, producing dozens of spurious warnings (IncorrectDelimiter, LowercaseKey, etc.). Consider either:

  1. Adding this file to a dotenv-linter exclusion/ignore list, or
  2. Renaming to e.g. .env.sh or scripts/load-env.sh and updating references.

Option 2 would also avoid confusing developers and other tools (IDEs, docker-compose, Node's dotenv library) that expect .env to be a flat key-value file.

scripts/sonar-scan.js (1)

193-240: Scanner directory sort assumes lexicographic ordering equals version ordering.

Line 228-229: .sort().reverse() picks the last directory alphabetically, which works for same-digit-count versions (e.g., sonar-scanner-5.0.1 vs sonar-scanner-6.0.0) but breaks for mixed-length major versions (sonar-scanner-9.x sorts after sonar-scanner-10.x lexicographically). This is an edge case that's unlikely today but worth noting.

Comment thread scripts/sonar-scan.js
Comment on lines +92 to +147
function loadEnvViaBash(projectRoot, lockedEnvKeys) {
if (!fs.existsSync(path.join(projectRoot, '.env'))) {
return [];
}

const shellScript = `
if [ -f "./.env.vault" ]; then
. ./.env.vault || true
fi
if [ -f "./.env" ]; then
set -a
. ./.env || true
set +a
fi
env -0
`;

const result = spawnSync('bash', ['-lc', shellScript], {
cwd: projectRoot,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'inherit'],
env: process.env,
});

if (result.error && result.error.code === 'ENOENT') {
return [];
}

if (result.error || result.status !== 0 || !result.stdout) {
return [];
}

const loadedKeys = [];
const entries = result.stdout.split('\0').filter(Boolean);
for (const entry of entries) {
const delimiterIndex = entry.indexOf('=');
if (delimiterIndex <= 0) {
continue;
}

const key = entry.slice(0, delimiterIndex);
const value = entry.slice(delimiterIndex + 1);
if (!shouldImportFromShell(key)) {
continue;
}

if (!shouldPreferDotenvValue(key, value, lockedEnvKeys)) {
continue;
}

process.env[key] = value;
loadedKeys.push(key);
}

return loadedKeys;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Vault helper log_info/log_warn write to stdout, corrupting the captured env -0 output.

loadEnvViaBash captures stdout from the spawned bash process (line 112: 'pipe'). When .env is sourced inside that subprocess, it calls vault_helper::load_from_definitions, which invokes vault_helper::log_info — and that writes to stdout (no >&2 redirect in vault-helper.sh lines 3-5, 7-9). These log lines get interleaved with the env -0 null-separated output, corrupting the first parsed entry and potentially injecting garbage key-value pairs (e.g., log lines containing =).

Two fixes needed in combination:

  1. In scripts/vault-helper.sh: redirect log_info and log_warn to stderr:
🐛 Fix in vault-helper.sh
 vault_helper::log_info() {
-    printf '[INFO] %s\n' "$1"
+    printf '[INFO] %s\n' "$1" >&2
 }

 vault_helper::log_warn() {
-    printf '[WARN] %s\n' "$1"
+    printf '[WARN] %s\n' "$1" >&2
 }
  1. Alternatively, in sonar-scan.js: redirect the subprocess stdout through a filter, or simply accept that bash-sourcing may produce extraneous output and add a more resilient parser (though fixing the root cause in the helper is cleaner).
🤖 Prompt for AI Agents
In `@scripts/sonar-scan.js` around lines 92 - 147, The spawned bash in
loadEnvViaBash is getting log lines from vault-helper.sh on stdout which corrupt
env -0 output; fix this by changing vault-helper.sh's log_info and log_warn to
write to stderr (use >&2 or redirect their prints to stderr) so they no longer
pollute stdout, and also make loadEnvViaBash more robust by sanitizing
result.stdout before parsing (e.g., drop any leading bytes up to the first NUL
or filter out lines/entries that don't look like valid KEY=VALUE pairs) in the
loadEnvViaBash function so stray helper output can't inject malformed entries.

Comment thread scripts/sonar-scan.js
Comment on lines 301 to +305
const projectKey =
process.env.SONAR_PROJECT_KEY || properties['sonar.projectKey'] || 'ai-code-prep';
process.env.SONAR_PROJECT_KEY ||
process.env.SONAR_PROJECT ||
properties['sonar.projectKey'] ||
'ai-code-prep';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Default project key 'ai-code-prep' appears stale.

The PR description, .env file (line 57: SONAR_PROJECT_KEY=ai-code-fusion), and the SonarQube logs all reference ai-code-fusion as the project key. The fallback on line 305 still uses 'ai-code-prep'.

-  properties['sonar.projectKey'] ||
-  'ai-code-prep';
+  properties['sonar.projectKey'] ||
+  'ai-code-fusion';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const projectKey =
process.env.SONAR_PROJECT_KEY || properties['sonar.projectKey'] || 'ai-code-prep';
process.env.SONAR_PROJECT_KEY ||
process.env.SONAR_PROJECT ||
properties['sonar.projectKey'] ||
'ai-code-prep';
const projectKey =
process.env.SONAR_PROJECT_KEY ||
process.env.SONAR_PROJECT ||
properties['sonar.projectKey'] ||
'ai-code-fusion';
🤖 Prompt for AI Agents
In `@scripts/sonar-scan.js` around lines 301 - 305, The default Sonar project key
fallback is stale: update the fallback value used when resolving projectKey (the
expression assigning to projectKey that checks process.env.SONAR_PROJECT_KEY,
process.env.SONAR_PROJECT, and properties['sonar.projectKey']) to use
'ai-code-fusion' instead of 'ai-code-prep' so the code, .env, and Sonar logs are
consistent.

Comment thread scripts/vault-helper.sh
Comment on lines +40 to +48
vault_helper::save_token() {
local token="$1"
local file="$2"
mkdir -p "$(dirname "$file")"
umask 077
printf '%s\n' "$token" >"$file"
chmod 600 "$file" 2>/dev/null || true
vault_helper::log_info "Saved Vault token to $file"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

umask 077 leaks into the caller's session.

Since this script is designed to be sourced (via .env), calling umask 077 on line 44 permanently changes the umask for the entire shell session, not just for the printf on line 45. All subsequent file creation by the user's shell will use the restrictive 077 mask.

Use a subshell to scope the umask change:

🛡️ Proposed fix
 vault_helper::save_token() {
     local token="$1"
     local file="$2"
     mkdir -p "$(dirname "$file")"
-    umask 077
-    printf '%s\n' "$token" >"$file"
-    chmod 600 "$file" 2>/dev/null || true
+    ( umask 077; printf '%s\n' "$token" >"$file" )
+    chmod 600 "$file" 2>/dev/null || true
     vault_helper::log_info "Saved Vault token to $file"
 }
🤖 Prompt for AI Agents
In `@scripts/vault-helper.sh` around lines 40 - 48, The vault_helper::save_token
function sets umask 077 globally which leaks into the caller's shell; change the
implementation to scope the umask to the write operation only (e.g., run the
mkdir/printf/chmod sequence inside a subshell or use a grouped command with a
locally-set umask) so the restrictive umask does not persist after the function
returns, and keep the vault_helper::log_info call outside or after the subshell
as needed.

Comment thread scripts/vault-helper.sh
Comment on lines +59 to +84
vault_helper::authenticate() {
local username password login_json token
read -r -p "Vault username: " username >&2
read -r -s -p "Vault password: " password
echo >&2

if ! login_json=$(vault login -format=json -method=userpass username="$username" password="$password" 2>/dev/null); then
vault_helper::log_error "Vault authentication failed"
return 1
fi

token=$(jq -r '.auth.client_token // empty' <<<"$login_json")
unset login_json

if [[ -z "$token" ]]; then
vault_helper::log_error "Vault login response did not include a token"
return 1
fi

VAULT_TOKEN="$token"
export VAULT_TOKEN
vault_helper::save_token "$token" "$VAULT_TOKEN_FILE"

unset username password token
return 0
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Password passed as a CLI argument is visible in the process list.

On line 65, password="$password" is passed as an argument to vault login. This makes the password visible to any user who can run ps on the same host. The vault CLI supports reading credentials from stdin or environment variables, which would be safer.

However, since this is an interactive local-dev flow (prompted credentials), the exposure window is brief and the risk is limited.

🤖 Prompt for AI Agents
In `@scripts/vault-helper.sh` around lines 59 - 84, In vault_helper::authenticate
change the vault login invocation so the password is not passed as a CLI
argument (avoid password="$password"); instead omit the password arg and feed
the password via stdin (e.g. pipe printf '%s\n' "$password" into the vault login
command or let vault prompt for the password) so the secret never appears in the
process list; update the login_json assignment that currently calls vault login
-format=json -method=userpass username="$username" password="$password" to the
stdin-based variant and keep the rest of the function (token extraction,
VAULT_TOKEN export, vault_helper::save_token) unchanged.

Comment thread scripts/vault-helper.sh
Comment on lines +141 to +149
if ! exports=$(printf '%s' "$data_json" | jq -r '
to_entries[]? |
"export \(.key)=\(.value | @sh)"
'); then
vault_helper::log_error "Unable to parse secrets from ${path}"
return 1
fi

eval "$exports"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

eval "$exports" is a command injection vector via unsanitized vault secret keys.

The jq template on line 143 embeds .key directly into the shell string without escaping. While .value is safely quoted with @sh, a vault key containing shell metacharacters (e.g., $(cmd) or backticks) would be executed. Even if vault keys are admin-controlled today, defense in depth matters here.

Quote the key with @sh as well:

🛡️ Proposed fix
     if ! exports=$(printf '%s' "$data_json" | jq -r '
         to_entries[]? |
-        "export \(.key)=\(.value | `@sh`)"
+        "export \(.key | `@sh`)=\(.value | `@sh`)"
     '); then

Alternatively, avoid eval entirely by iterating keys with jq -r 'keys[]' and assigning via printf -v / export, similar to the set_secret_if_empty pattern already in this file.

🤖 Prompt for AI Agents
In `@scripts/vault-helper.sh` around lines 141 - 149, The current use of eval
"$exports" after building export lines from data_json is a command-injection
risk because the jq template embeds .key unescaped; change this to either (a)
escape keys with `@sh` in the jq output so both key and value are safely quoted
before eval, or (b) eliminate eval entirely by iterating over keys parsed from
data_json (e.g., using jq -r 'keys[]' or to_entries[]), and for each key use a
safe assignment pattern like printf -v / export (the same approach used by
set_secret_if_empty) to set environment variables; ensure you update the error
path that calls vault_helper::log_error when parsing fails and keep the behavior
of returning 1 on error.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (3) 📎 Requirement gaps (0)

Grey Divider


Action required

1. sonar.token passed via CLI 📘 Rule violation ⛨ Security
Description
• The native scanner path uses spawnSync(scannerBinary, args, ...) where args are built as
  -D${key}=${value}, which will include the Sonar token when scannerOptions['sonar.token'] is set.
• Passing secrets via command-line arguments can expose tokens via process listings and CI/job
  telemetry, violating secure handling requirements for sensitive data.
Code

scripts/sonar-scan.js[R173-180]

+  console.log(`Using native sonar-scanner: ${scannerBinary}`);
+  const args = Object.entries(scannerOptions).map(([key, value]) => `-D${key}=${value}`);
+  const useWindowsShell = process.platform === 'win32' && scannerBinary.toLowerCase().endsWith('.bat');
+  const result = spawnSync(scannerBinary, args, {
+    cwd: projectRoot,
+    stdio: 'inherit',
+    shell: useWindowsShell,
+  });
Evidence
Compliance requires sensitive data not be exposed. The PR constructs CLI arguments from all scanner
options and conditionally inserts sonar.token, which results in the token being sent on the
command line.

Rule 6: Generic: Security-First Input Validation and Data Handling
scripts/sonar-scan.js[173-180]
scripts/sonar-scan.js[332-334]

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 implementation passes the Sonar token via `-Dsonar.token=...` on the command line when using the native scanner. CLI arguments can be observable (e.g., process list, CI logs/telemetry), which can leak secrets.

## Issue Context
This occurs in the native scanner execution path where all scanner options are converted to `-Dkey=value` arguments, and `sonar.token` is added when `SONAR_TOKEN` is present.

## Fix Focus Areas
- scripts/sonar-scan.js[173-180]
- scripts/sonar-scan.js[332-334]

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


2. Windows sonar env broken 🐞 Bug ✓ Correctness
Description
make.bat still assumes .env is a line-oriented KEY=VALUE file, but this PR converts .env
  into a bash script.
• On Windows, make sonar will not load SONAR_* variables correctly, so npm run sonar may run
  with missing config (and now defaults to localhost).
• This is a breaking change for Windows developers using make.bat sonar.
Code

.env[R3-13]

+#!/usr/bin/env bash
+
+# Vault environment loader wrapper
+# Usage: source .env (never run directly)
+
+set -o pipefail
+
+if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
+    echo "This script must be sourced: source .env" >&2
+    exit 1
+fi
Evidence
The new .env is a bash script (shebang + [[ ... ]] + source), but make.bat reads .env
line-by-line and splits on = to set variables. Those parsers are incompatible, so Windows will not
reliably load the intended environment variables.

.env[3-13]
make.bat[30-50]

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

### Issue description
`make.bat sonar` expects `.env` to be a simple `KEY=VALUE` file, but `.env` is now a bash script. This breaks environment loading on Windows.

### Issue Context
Windows batch parsing cannot interpret bash constructs (`#!/usr/bin/env bash`, `[[ ... ]]`, `source`, function calls). As a result, SONAR-related env vars won&#x27;t be loaded.

### Fix Focus Areas
- .env[1-58]
- make.bat[30-50]

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


3. Stdout corrupts env import 🐞 Bug ⛯ Reliability
Description
scripts/sonar-scan.js captures stdout from a bash subshell and assumes it contains only env -0
  output.
• The sourced .env/Vault helper prints informational logs to **stdout**, so those logs get
  prepended into the captured buffer and can corrupt the NUL-delimited parsing.
• This can lead to missing/incorrect SONAR_*/VAULT_* imports even when Vault loading succeeds.
Code

scripts/sonar-scan.js[R97-145]

+  const shellScript = `
+if [ -f "./.env.vault" ]; then
+  . ./.env.vault || true
+fi
+if [ -f "./.env" ]; then
+  set -a
+  . ./.env || true
+  set +a
+fi
+env -0
+`;
+
+  const result = spawnSync('bash', ['-lc', shellScript], {
+    cwd: projectRoot,
+    encoding: 'utf8',
+    stdio: ['inherit', 'pipe', 'inherit'],
+    env: process.env,
+  });
+
+  if (result.error && result.error.code === 'ENOENT') {
+    return [];
+  }
+
+  if (result.error || result.status !== 0 || !result.stdout) {
+    return [];
+  }
+
+  const loadedKeys = [];
+  const entries = result.stdout.split('\0').filter(Boolean);
+  for (const entry of entries) {
+    const delimiterIndex = entry.indexOf('=');
+    if (delimiterIndex <= 0) {
+      continue;
+    }
+
+    const key = entry.slice(0, delimiterIndex);
+    const value = entry.slice(delimiterIndex + 1);
+    if (!shouldImportFromShell(key)) {
+      continue;
+    }
+
+    if (!shouldPreferDotenvValue(key, value, lockedEnvKeys)) {
+      continue;
+    }
+
+    process.env[key] = value;
+    loadedKeys.push(key);
+  }
+
Evidence
The bash loader runs . ./.env and then env -0, while Node captures stdout and splits on \0.
Any stdout emitted during .env sourcing (Vault helper [INFO] logs) is mixed into the same stdout
stream and can break the parsing assumptions.

scripts/sonar-scan.js[97-107]
scripts/sonar-scan.js[109-114]
scripts/sonar-scan.js[124-145]
scripts/vault-helper.sh[3-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
`loadEnvViaBash()` parses `env -0` from stdout, but `.env`/Vault helper emits logs to stdout, corrupting the NUL-delimited env stream.

### Issue Context
Any stdout before `env -0` becomes part of the captured buffer and breaks the parser’s assumptions.

### Fix Focus Areas
- scripts/sonar-scan.js[92-147]
- scripts/vault-helper.sh[3-13]

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


View more (1)
4. Vault prompts can hang 🐞 Bug ⛯ Reliability
Description
.env unconditionally calls vault_helper::load_from_definitions, which may invoke interactive
  read prompts when a token is missing/invalid.
• scripts/sonar-scan.js runs .env inside a spawned bash with stdin inherited; in
  non-interactive contexts this can block until timeout.
• This makes npm run sonar fragile on machines that have vault+jq installed but no valid token
  file/env configured.
Code

.env[R44-47]

+SECRET_DEFS="${VAULT_SECRET_PATHS:-$DEFAULT_VAULT_SECRET_DEFS}"
+REQUIRED_VARS="${VAULT_REQUIRED_VARS:-$DEFAULT_VAULT_REQUIRED_VARS}"
+
+vault_helper::load_from_definitions "$SECRET_DEFS" "$REQUIRED_VARS" "$VAULT_TOKEN_FILE"
Evidence
The .env script always triggers Vault loading. The helper will fall back to interactive
authentication (read username/password) if the token is missing/invalid. Because sonar-scan.js
runs the bash loader with inherited stdin, a non-interactive run can hang.

.env[44-47]
scripts/vault-helper.sh[59-67]
scripts/vault-helper.sh[213-220]
scripts/sonar-scan.js[109-114]

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

### Issue description
Running `.env` can trigger interactive Vault login prompts, which can hang `npm run sonar` in non-interactive environments.

### Issue Context
`.env` always calls `vault_helper::load_from_definitions`, and the helper will prompt via `read` if a token is missing/invalid.

### Fix Focus Areas
- .env[29-47]
- scripts/vault-helper.sh[59-84]
- scripts/vault-helper.sh[205-220]
- scripts/sonar-scan.js[92-147]

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



Remediation recommended

5. .env.vault is sourced 📘 Rule violation ⛨ Security
Description
• The scan script runs a bash snippet that sources ./.env.vault (and ./.env) directly, which
  allows arbitrary shell commands in those files to execute.
• This treats a local file as executable input without validation/sanitization, increasing the risk
  of command injection or unintended execution when running QA/CI tooling.
Code

scripts/sonar-scan.js[R97-105]

+  const shellScript = `
+if [ -f "./.env.vault" ]; then
+  . ./.env.vault || true
+fi
+if [ -f "./.env" ]; then
+  set -a
+  . ./.env || true
+  set +a
+fi
Evidence
Compliance requires external inputs (including file-based configuration) be validated and handled
securely. The PR explicitly sources .env.vault/.env in a shell, executing any content in those
files rather than parsing key/value pairs safely.

Rule 6: Generic: Security-First Input Validation and Data Handling
scripts/sonar-scan.js[97-105]

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 code sources `.env.vault` and `.env` via bash, which executes arbitrary shell content. This is unsafe for configuration inputs and can lead to command execution.

## Issue Context
The `loadEnvViaBash()` helper constructs a shell script that runs `. ./.env.vault` and `. ./.env`.

## Fix Focus Areas
- scripts/sonar-scan.js[97-105]

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


6. Env load errors ignored 📘 Rule violation ⛯ Reliability
Description
• Failures during env loading are intentionally ignored (|| true) and loadEnvViaBash() returns
  an empty set on non-zero status/error without emitting actionable diagnostics.
• This creates silent failure modes that make it difficult to detect misconfiguration (e.g., missing
  Vault auth, syntax errors), reducing robustness and debuggability.
Code

scripts/sonar-scan.js[R120-122]

+  if (result.error || result.status !== 0 || !result.stdout) {
+    return [];
+  }
Evidence
The checklist requires meaningful handling of failure points with actionable context. Here, env-load
failures are suppressed and converted into an empty result, preventing users/CI from understanding
what failed and why.

Rule 3: Generic: Robust Error Handling and Edge Case Management
scripts/sonar-scan.js[98-105]
scripts/sonar-scan.js[120-122]

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

## Issue description
Environment loading can fail silently due to `|| true` and empty-array returns on shell errors, making debugging difficult.

## Issue Context
`loadEnvViaBash()` suppresses errors from sourcing `.env` files and drops failures without logging diagnostics.

## Fix Focus Areas
- scripts/sonar-scan.js[98-105]
- scripts/sonar-scan.js[120-122]েষ্ট

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


7. Sourcing side effects persist 🐞 Bug ⛯ Reliability
Description
.env is meant to be sourced, but it changes shell state (set -o pipefail) and the Vault helper
  changes process umask (umask 077) without restoring either.
• .env also sets DTR_PROJECT_KEY= (empty), which can unintentionally clear a previously
  configured value in the current shell.
• These side effects persist in the developer’s shell session after sourcing and can cause
  surprising downstream behavior.
Code

.env[R8-55]

+set -o pipefail
+
+if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
+    echo "This script must be sourced: source .env" >&2
+    exit 1
+fi
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+HELPER_PATH="${VAULT_HELPER_PATH:-${SCRIPT_DIR}/scripts/vault-helper.sh}"
+
+if [[ ! -r "$HELPER_PATH" ]]; then
+    echo "Vault helper not found at $HELPER_PATH" >&2
+    return 1
+fi
+
+# shellcheck source=./scripts/vault-helper.sh
+source "$HELPER_PATH"
+
+DEFAULT_VAULT_SECRET_DEFS=$'kv/Sonarqube/sonarqube|SONAR_TOKEN=SONAR_TOKEN SONAR_TOKEN=sonar_token SONAR_TOKEN=token\nkv/dependencytrack|DTRACK_API_KEY=DTRACK_API_KEY DTRACK_API_KEY=api_key DTRACK_API_KEY=token'
+DEFAULT_VAULT_REQUIRED_VARS="SONAR_TOKEN DTRACK_API_KEY"
+
+if [[ -z "${VAULT_TOKEN:-}" ]]; then
+    token_candidates=()
+    if [[ -n "${VAULT_TOKEN_FILE:-}" ]]; then
+        token_candidates+=("$VAULT_TOKEN_FILE")
+    fi
+    token_candidates+=("${HOME}/.vault-token" "/home/vscode/.vault-token" "/root/.vault-token")
+    for token_path in "${token_candidates[@]}"; do
+        if [[ -r "$token_path" ]]; then
+            VAULT_TOKEN_FILE="$token_path"
+            export VAULT_TOKEN_FILE
+            break
+        fi
+    done
+fi
+
+SECRET_DEFS="${VAULT_SECRET_PATHS:-$DEFAULT_VAULT_SECRET_DEFS}"
+REQUIRED_VARS="${VAULT_REQUIRED_VARS:-$DEFAULT_VAULT_REQUIRED_VARS}"
+
+vault_helper::load_from_definitions "$SECRET_DEFS" "$REQUIRED_VARS" "$VAULT_TOKEN_FILE"
+
+# Commented out for CI/automated testing
+# SONAR_TOKEN=""
+DTR_PROJECT_KEY=
+# DTRACK_API_KEY=""
+DTRACK_PROJECT=ai-code-fusion
+DTRACK_PROJECT_VERSION=main
+
Evidence
When sourced, .env runs in the caller’s shell context. set -o pipefail and umask 077 will
remain in effect unless explicitly restored. Additionally, setting DTR_PROJECT_KEY to an empty
value will overwrite any previously set value in that shell.

.env[8-9]
.env[49-55]
scripts/vault-helper.sh[40-48]

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

### Issue description
Sourcing `.env` should not permanently change the caller’s shell state (pipefail/umask) or clear existing env values.

### Issue Context
Because `.env` is sourced, `set -o pipefail` and `umask 077` persist in the user’s shell session unless restored.

### Fix Focus Areas
- .env[5-13]
- .env[49-55]
- scripts/vault-helper.sh[40-48]

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


View more (1)
8. Vault JSON capture fragile 🐞 Bug ⛨ Security
Description
vault kv get -format=json output is captured with 2>&1, so warnings printed to stderr can be
  merged into stdout and break JSON parsing.
• Secrets are exported via eval of generated export KEY=... lines; values are quoted, but keys
  aren’t validated, so an unexpected key can cause syntax errors or odd exports.
• This is likely low risk with controlled Vault data, but it’s a sharp edge for reliability and
  defense-in-depth.
Code

scripts/vault-helper.sh[R124-150]

+    vault_helper::log_info "Fetching secrets from ${path}..."
+    if ! payload=$(vault kv get -format=json "$path" 2>&1); then
+        vault_helper::log_error "Failed to fetch secrets from ${path}"
+        vault_helper::log_error "$payload"
+        return 1
+    fi
+
+    if ! data_json=$(printf '%s' "$payload" | jq -c '.data.data // .data // {}'); then
+        vault_helper::log_error "Unable to parse secrets JSON from ${path}"
+        return 1
+    fi
+
+    if [[ "$data_json" == "{}" ]]; then
+        vault_helper::log_warn "No secrets to export at ${path}"
+        return 0
+    fi
+
+    if ! exports=$(printf '%s' "$data_json" | jq -r '
+        to_entries[]? |
+        "export \(.key)=\(.value | @sh)"
+    '); then
+        vault_helper::log_error "Unable to parse secrets from ${path}"
+        return 1
+    fi
+
+    eval "$exports"
+    vault_helper::apply_mappings "$data_json" "$path" "$mappings"
Evidence
The helper merges stdout+stderr into payload and then runs jq on it, which can fail if any
non-JSON text is mixed in. It then constructs shell export statements and executes them with
eval; without validating that .key is a legal env var name, unusual keys can break execution.

scripts/vault-helper.sh[124-133]
scripts/vault-helper.sh[141-150]

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

### Issue description
Vault helper mixes stderr into JSON and uses `eval` for exporting secrets, which is fragile and makes key validation difficult.

### Issue Context
Warnings/logging from Vault on stderr can break JSON parsing; unexpected keys can cause shell syntax errors.

### Fix Focus Areas
- scripts/vault-helper.sh[119-155]

ⓘ 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/sonar-scan.js
Comment on lines +173 to +180
console.log(`Using native sonar-scanner: ${scannerBinary}`);
const args = Object.entries(scannerOptions).map(([key, value]) => `-D${key}=${value}`);
const useWindowsShell = process.platform === 'win32' && scannerBinary.toLowerCase().endsWith('.bat');
const result = spawnSync(scannerBinary, args, {
cwd: projectRoot,
stdio: 'inherit',
shell: useWindowsShell,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. sonar.token passed via cli 📘 Rule violation ⛨ Security

• The native scanner path uses spawnSync(scannerBinary, args, ...) where args are built as
  -D${key}=${value}, which will include the Sonar token when scannerOptions['sonar.token'] is set.
• Passing secrets via command-line arguments can expose tokens via process listings and CI/job
  telemetry, violating secure handling requirements for sensitive data.
Agent Prompt
## Issue description
The implementation passes the Sonar token via `-Dsonar.token=...` on the command line when using the native scanner. CLI arguments can be observable (e.g., process list, CI logs/telemetry), which can leak secrets.

## Issue Context
This occurs in the native scanner execution path where all scanner options are converted to `-Dkey=value` arguments, and `sonar.token` is added when `SONAR_TOKEN` is present.

## Fix Focus Areas
- scripts/sonar-scan.js[173-180]
- scripts/sonar-scan.js[332-334]

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

Comment thread .env
Comment on lines +3 to +13
#!/usr/bin/env bash

# Vault environment loader wrapper
# Usage: source .env (never run directly)

set -o pipefail

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
echo "This script must be sourced: source .env" >&2
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Windows sonar env broken 🐞 Bug ✓ Correctness

make.bat still assumes .env is a line-oriented KEY=VALUE file, but this PR converts .env
  into a bash script.
• On Windows, make sonar will not load SONAR_* variables correctly, so npm run sonar may run
  with missing config (and now defaults to localhost).
• This is a breaking change for Windows developers using make.bat sonar.
Agent Prompt
### Issue description
`make.bat sonar` expects `.env` to be a simple `KEY=VALUE` file, but `.env` is now a bash script. This breaks environment loading on Windows.

### Issue Context
Windows batch parsing cannot interpret bash constructs (`#!/usr/bin/env bash`, `[[ ... ]]`, `source`, function calls). As a result, SONAR-related env vars won't be loaded.

### Fix Focus Areas
- .env[1-58]
- make.bat[30-50]

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

Comment thread scripts/sonar-scan.js
Comment on lines +97 to +145
const shellScript = `
if [ -f "./.env.vault" ]; then
. ./.env.vault || true
fi
if [ -f "./.env" ]; then
set -a
. ./.env || true
set +a
fi
env -0
`;

const result = spawnSync('bash', ['-lc', shellScript], {
cwd: projectRoot,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'inherit'],
env: process.env,
});

if (result.error && result.error.code === 'ENOENT') {
return [];
}

if (result.error || result.status !== 0 || !result.stdout) {
return [];
}

const loadedKeys = [];
const entries = result.stdout.split('\0').filter(Boolean);
for (const entry of entries) {
const delimiterIndex = entry.indexOf('=');
if (delimiterIndex <= 0) {
continue;
}

const key = entry.slice(0, delimiterIndex);
const value = entry.slice(delimiterIndex + 1);
if (!shouldImportFromShell(key)) {
continue;
}

if (!shouldPreferDotenvValue(key, value, lockedEnvKeys)) {
continue;
}

process.env[key] = value;
loadedKeys.push(key);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Stdout corrupts env import 🐞 Bug ⛯ Reliability

scripts/sonar-scan.js captures stdout from a bash subshell and assumes it contains only env -0
  output.
• The sourced .env/Vault helper prints informational logs to **stdout**, so those logs get
  prepended into the captured buffer and can corrupt the NUL-delimited parsing.
• This can lead to missing/incorrect SONAR_*/VAULT_* imports even when Vault loading succeeds.
Agent Prompt
### Issue description
`loadEnvViaBash()` parses `env -0` from stdout, but `.env`/Vault helper emits logs to stdout, corrupting the NUL-delimited env stream.

### Issue Context
Any stdout before `env -0` becomes part of the captured buffer and breaks the parser’s assumptions.

### Fix Focus Areas
- scripts/sonar-scan.js[92-147]
- scripts/vault-helper.sh[3-13]

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

Comment thread .env
Comment on lines +44 to +47
SECRET_DEFS="${VAULT_SECRET_PATHS:-$DEFAULT_VAULT_SECRET_DEFS}"
REQUIRED_VARS="${VAULT_REQUIRED_VARS:-$DEFAULT_VAULT_REQUIRED_VARS}"

vault_helper::load_from_definitions "$SECRET_DEFS" "$REQUIRED_VARS" "$VAULT_TOKEN_FILE"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Vault prompts can hang 🐞 Bug ⛯ Reliability

.env unconditionally calls vault_helper::load_from_definitions, which may invoke interactive
  read prompts when a token is missing/invalid.
• scripts/sonar-scan.js runs .env inside a spawned bash with stdin inherited; in
  non-interactive contexts this can block until timeout.
• This makes npm run sonar fragile on machines that have vault+jq installed but no valid token
  file/env configured.
Agent Prompt
### Issue description
Running `.env` can trigger interactive Vault login prompts, which can hang `npm run sonar` in non-interactive environments.

### Issue Context
`.env` always calls `vault_helper::load_from_definitions`, and the helper will prompt via `read` if a token is missing/invalid.

### Fix Focus Areas
- .env[29-47]
- scripts/vault-helper.sh[59-84]
- scripts/vault-helper.sh[205-220]
- scripts/sonar-scan.js[92-147]

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

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/sonar-scan.js (2)

265-270: ⚠️ Potential issue | 🟡 Minor

Raw URL leaked in error log despite redaction elsewhere.

Line 268 logs the full sonarUrl in the error message, but line 273 redacts it via redactUrlForLogs. For consistency with the redaction policy, this error path should also redact.

Proposed fix
-  console.error(`Error: SONAR_URL is not a valid URL: ${sonarUrl}`);
+  console.error(`Error: SONAR_URL is not a valid URL: ${redactUrlForLogs(sonarUrl)}`);

289-308: ⚠️ Potential issue | 🟠 Major

Unhandled crash if sonar-project.properties is missing.

fs.readFileSync on line 291 throws ENOENT if the file doesn't exist, and this code runs outside the try/catch block (line 323). The script will crash with an unhandled exception instead of falling back to defaults.

Proposed fix
 const propertiesPath = path.join(__dirname, '..', 'sonar-project.properties');
-const propertiesContent = fs.readFileSync(propertiesPath, 'utf8');
 const properties = {};
 
-// Simple parser for properties file
-propertiesContent.split('\n').forEach((line) => {
-  line = line.trim();
-  if (line && !line.startsWith('#')) {
-    const delimiterIndex = line.indexOf('=');
-    if (delimiterIndex === -1) {
-      return;
-    }
-    const key = line.slice(0, delimiterIndex).trim();
-    const value = line.slice(delimiterIndex + 1).trim();
-    if (key && value) {
-      properties[key] = value;
+if (fs.existsSync(propertiesPath)) {
+  const propertiesContent = fs.readFileSync(propertiesPath, 'utf8');
+  propertiesContent.split('\n').forEach((line) => {
+    line = line.trim();
+    if (line && !line.startsWith('#')) {
+      const delimiterIndex = line.indexOf('=');
+      if (delimiterIndex === -1) {
+        return;
+      }
+      const key = line.slice(0, delimiterIndex).trim();
+      const value = line.slice(delimiterIndex + 1).trim();
+      if (key && value) {
+        properties[key] = value;
+      }
     }
-  }
-});
+  });
+} else {
+  console.warn('sonar-project.properties not found; using defaults');
+}
🤖 Fix all issues with AI agents
In @.github/workflows/secrets-gate.yml:
- Around line 25-33: Add SHA256 checksum verification for the downloaded
gitleaks release: in the "Install gitleaks" step (where GITLEAKS_VERSION is used
and gitleaks.tar.gz is saved), also curl the corresponding checksums file from
the same release, extract the expected checksum for
gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz, compute the SHA256 of the
downloaded gitleaks.tar.gz (e.g., using sha256sum) and compare them, and exit
non‑zero if they do not match; alternatively replace this manual install with
the official gitleaks/gitleaks-action which performs verification automatically.

In `@scripts/sonar-scan.js`:
- Around line 184-190: The spawnSync call can break on Windows when
useWindowsShell is true because cmd.exe will interpret metacharacters in the
`args` built from `scannerOptions`; update the logic around `scannerBinary`,
`useWindowsShell`, `args`, and the `spawnSync` invocation to avoid cmd.exe
parsing: prefer the `.exe` scanner if available (check for an `.exe` sibling of
`scannerBinary` and use it instead), and if you must invoke the `.bat`,
wrap/escape each `-D${key}=${value}` arg for cmd.exe (quote each argument and
escape internal quotes/percent signs appropriately) before passing to
`spawnSync` with `shell: true`; alternatively, set `shell: false` and invoke the
`.bat` via `cmd.exe /c` with safely quoted arguments to ensure metacharacters
are not treated by the shell.
🧹 Nitpick comments (3)
scripts/capture-ui-screenshot.js (1)

379-388: Consider explicit timeouts on waitForFunction calls for consistency.

Throughout the file, waitForSelector and waitFor calls use an explicit { timeout: 10000 }, but the three waitForFunction calls (lines 380, 421, 443) rely on Playwright's default 30 s timeout. If the intent is to fail fast on broken UI, adding an explicit timeout would keep behaviour consistent and make the expected wait budget obvious to future maintainers.

Example for one of the call sites
-    await page.waitForFunction((totalFiles) => {
-      const fileTreeRoot = document.querySelector('.file-tree');
-      if (!fileTreeRoot) {
-        return false;
-      }
-      const summaryText = fileTreeRoot.textContent || '';
-      return summaryText.includes(`of ${totalFiles} files selected`);
-    }, MOCK_TOTAL_FILE_COUNT);
+    await page.waitForFunction((totalFiles) => {
+      const fileTreeRoot = document.querySelector('.file-tree');
+      if (!fileTreeRoot) {
+        return false;
+      }
+      const summaryText = fileTreeRoot.textContent || '';
+      return summaryText.includes(`of ${totalFiles} files selected`);
+    }, MOCK_TOTAL_FILE_COUNT, { timeout: 10000 });

Also applies to: 420-428, 442-446

.github/workflows/secrets-gate.yml (2)

35-46: Single-SHA fallback scans the entire history — confirm this is intentional.

When github.event.before is all zeros (new branch push) or on workflow_dispatch, Line 45 emits a single SHA. Passing that to gitleaks git --log-opts=<sha> is equivalent to git log <sha>, which walks the commit and all its ancestors — a full-history scan. This is a sensible default for a first-push or manual audit, but it's worth adding an inline comment so future maintainers don't mistake it for a single-commit scan.


19-23: Add version comments to pinned SHA references for maintainability.

Pinned commit SHAs ensure supply-chain security, but become opaque over time. A trailing version comment clarifies which release is deployed. Both actions in this file should be updated with their corresponding version tags.

📝 Suggested changes
      - name: Checkout repository
-        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
+        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.0
      - name: Upload gitleaks report
         if: always()
-        uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
+        uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0

Comment on lines +25 to +33
- name: Install gitleaks
env:
GITLEAKS_VERSION: 8.24.3
run: |
set -euo pipefail
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o gitleaks.tar.gz
tar -xzf gitleaks.tar.gz gitleaks
chmod +x gitleaks
echo "${PWD}" >> "${GITHUB_PATH}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

gitleaks releases GitHub checksums SHA256

💡 Result:

Yes—Gitleaks publishes SHA256 checksums on GitHub Releases:

  • In each release, there is a dedicated asset named like gitleaks_<version>_checksums.txt (e.g., gitleaks_8.30.0_checksums.txt) that contains SHA256 hashes for the release artifacts. [1]
  • Additionally, GitHub itself displays an SHA256 digest next to each uploaded release asset (computed by GitHub at upload time), so you can verify without relying only on the project-provided checksum file. [2]

To verify locally, GitHub recommends using the CLI command gh release verify-asset <tag> <artifact-path>. [3]

Sources: [1] [2] [3]


🌐 Web query:

gitleaks-action GitHub official repository

💡 Result:

The official GitHub repository for gitleaks-action is gitleaks/gitleaks-action. [1]

https://github.com/gitleaks/gitleaks-action

Verify the downloaded gitleaks binary's checksum to mitigate supply-chain risk.

The gitleaks binary is fetched directly from GitHub Releases without verifying its SHA256 digest. If the release asset were ever tampered with, a malicious binary would be installed silently. Gitleaks publishes SHA256 checksums for each release in a dedicated checksum file, and GitHub also displays digests alongside each asset.

🔒 Proposed fix — add checksum verification
       - name: Install gitleaks
         env:
           GITLEAKS_VERSION: 8.24.3
+          GITLEAKS_SHA256: "<expected-sha256-for-linux-x64-tarball>"
         run: |
           set -euo pipefail
           curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o gitleaks.tar.gz
+          echo "${GITLEAKS_SHA256}  gitleaks.tar.gz" | sha256sum -c -
           tar -xzf gitleaks.tar.gz gitleaks
           chmod +x gitleaks
           echo "${PWD}" >> "${GITHUB_PATH}"

Alternatively, use the official gitleaks/gitleaks-action, which handles installation and verification automatically.

🤖 Prompt for AI Agents
In @.github/workflows/secrets-gate.yml around lines 25 - 33, Add SHA256 checksum
verification for the downloaded gitleaks release: in the "Install gitleaks" step
(where GITLEAKS_VERSION is used and gitleaks.tar.gz is saved), also curl the
corresponding checksums file from the same release, extract the expected
checksum for gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz, compute the SHA256
of the downloaded gitleaks.tar.gz (e.g., using sha256sum) and compare them, and
exit non‑zero if they do not match; alternatively replace this manual install
with the official gitleaks/gitleaks-action which performs verification
automatically.

Comment thread scripts/sonar-scan.js
Comment on lines +184 to +190
const args = Object.entries(scannerOptions).map(([key, value]) => `-D${key}=${value}`);
const useWindowsShell = process.platform === 'win32' && scannerBinary.toLowerCase().endsWith('.bat');
const result = spawnSync(scannerBinary, args, {
cwd: projectRoot,
stdio: 'inherit',
shell: useWindowsShell,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

On Windows with .bat scanner, shell: true can misinterpret special characters in -D arguments.

When useWindowsShell is true, spawnSync delegates to cmd.exe, which interprets shell metacharacters (&, |, ^, >, etc.) in the argument values. If any scanner option value contains these characters (e.g., from sonar.exclusions glob patterns), the command may break or behave unexpectedly.

Consider quoting each argument for cmd.exe or using the .exe variant of the scanner if available.

🤖 Prompt for AI Agents
In `@scripts/sonar-scan.js` around lines 184 - 190, The spawnSync call can break
on Windows when useWindowsShell is true because cmd.exe will interpret
metacharacters in the `args` built from `scannerOptions`; update the logic
around `scannerBinary`, `useWindowsShell`, `args`, and the `spawnSync`
invocation to avoid cmd.exe parsing: prefer the `.exe` scanner if available
(check for an `.exe` sibling of `scannerBinary` and use it instead), and if you
must invoke the `.bat`, wrap/escape each `-D${key}=${value}` arg for cmd.exe
(quote each argument and escape internal quotes/percent signs appropriately)
before passing to `spawnSync` with `shell: true`; alternatively, set `shell:
false` and invoke the `.bat` via `cmd.exe /c` with safely quoted arguments to
ensure metacharacters are not treated by the shell.

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/renderer/components/SourceTab.tsx (1)

247-256: ⚠️ Potential issue | 🟡 Minor

forEach callbacks implicitly return a value (Biome lint error).

onFileSelect / onFolderSelect (typed as SelectionHandler) may return a value. Arrow shorthand (x) => fn(x) implicitly returns it, which is flagged by Biome for forEach callbacks since the return value is discarded. Use a block body to silence this and make intent explicit.

Proposed fix
-                selectedFiles.forEach((filePath) => onFileSelect(filePath, false));
-                selectedFolders.forEach((folderPath) => onFolderSelect(folderPath, false));
+                selectedFiles.forEach((filePath) => { onFileSelect(filePath, false); });
+                selectedFolders.forEach((folderPath) => { onFolderSelect(folderPath, false); });
.gitignore (1)

64-67: ⚠️ Potential issue | 🟡 Minor

Consider using .env.example instead of committing .env.

The .env file is currently tracked by git (it's not listed in .gitignore). While the current file contains only Vault loader scaffolding with no actual secrets, this pattern deviates from standard security practices and creates risk for future development:

  • Even with good intentions, developers may accidentally add secrets to .env
  • Shared secret reference paths (e.g., kv/Sonarqube/sonarqube, kv/dependencytrack) in a committed file can leak vault structure information
  • The wildcard pattern .env.* protects environment-specific files, but the base .env remains exposed

Recommended approach: Add .env to .gitignore (line 65) and create .env.example to document the Vault loader structure for developers to copy locally. This maintains the scaffolding benefits while following security best practices.

Current .gitignore section
# Environment variables and local config
.env.local
.env.*
.scannerwork/
🤖 Fix all issues with AI agents
In `@src/renderer/components/ProcessedTab.tsx`:
- Line 214: The element in ProcessedTab.tsx uses conflicting Tailwind utilities
"min-h-48" and "min-h-0" in the className string; remove the one that does not
match the intended behavior (keep "min-h-48" only if you want a 12rem minimum
height, or keep "min-h-0" only if you need the element to fully shrink in a flex
container) and update the className on the element that currently reads
"min-h-48 min-h-0 flex-1 overflow-auto rounded-md border ..." accordingly.
🧹 Nitpick comments (1)
src/renderer/components/TabBar.tsx (1)

17-34: ARIA tab roles are well-applied; consider adding keyboard navigation for full compliance.

The role="tablist", role="tab", aria-selected, and aria-controls attributes correctly implement the ARIA tabs pattern. However, the WAI-ARIA Tabs Pattern also expects:

  • tabIndex={activeTab === tab.id ? 0 : -1} so only the active tab is in the tab sequence.
  • Arrow-key navigation between tabs (ArrowLeft/ArrowRight).

This is not a blocker but would complete the accessibility story.

<div
id='processed-content'
className='max-h-[45vh] min-h-48 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
className='min-h-48 min-h-0 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Conflicting Tailwind min-h utilities: min-h-48 and min-h-0.

Both min-h-48 (12rem) and min-h-0 (0px) are applied to the same element. In Tailwind, the winner depends on CSS specificity/order in the generated stylesheet, which is non-deterministic from the class list order in HTML. If you want a minimum height with flex shrinking, use only min-h-48. If you need the element to shrink below that in a flex context, min-h-0 alone is correct.

Proposed fix (pick one intent)

If the intent is a 12rem minimum:

-              className='min-h-48 min-h-0 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
+              className='min-h-48 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'

If the intent is to allow full flex shrinking:

-              className='min-h-48 min-h-0 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
+              className='min-h-0 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
className='min-h-48 min-h-0 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
className='min-h-48 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
Suggested change
className='min-h-48 min-h-0 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
className='min-h-0 flex-1 overflow-auto rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-700 p-4 shadow-sm'
🤖 Prompt for AI Agents
In `@src/renderer/components/ProcessedTab.tsx` at line 214, The element in
ProcessedTab.tsx uses conflicting Tailwind utilities "min-h-48" and "min-h-0" in
the className string; remove the one that does not match the intended behavior
(keep "min-h-48" only if you want a 12rem minimum height, or keep "min-h-0" only
if you need the element to fully shrink in a flex container) and update the
className on the element that currently reads "min-h-48 min-h-0 flex-1
overflow-auto rounded-md border ..." accordingly.

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