Skip to content

Diff-View

1. Overview

The Diff View is a feature integrated into the SecAI SonarQube plugin that provides a side-by-side comparison between a piece of code with a known vulnerability and the secure code snippet generated by the AI Fix feature. Its primary purpose is to offer developers a clear and immediate visualization of the changes proposed by the AI, facilitating a quick review and validation process.


2. Technical Implementation

The feature is implemented on the frontend using React and Redux for state management. It involves a main view component that orchestrates the display of tabs, a new dedicated component for rendering the diff, and the Redux store for managing the state of the code snippets.

2.1. Core Components

DiffView.js

This is a new, specialized component responsible for rendering the code comparison. - Purpose: To display a side-by-side diff of the original (vulnerable) code and the AI-generated (fixed) code. - Dependency: It utilizes the react-diff-viewer-continued library to handle the complexities of diff rendering, including line-by-line highlighting of additions and deletions. - Props: - oldCode: A string containing the original source code snippet. - newCode: A string containing the AI-generated secure code snippet.

File: main/js/sec_ai/components/Description/DiffView.js

import React from 'react';
import ReactDiffViewer from 'react-diff-viewer-continued';
import 'react-diff-viewer-continued/dist/style.css';

const DiffView = ({ oldCode, newCode }) => {
    if (!oldCode || !newCode) {
        return <p>Not enough data to display the diff.</p>;
    }

    return (
        <ReactDiffViewer
            oldValue={oldCode}
            newValue={newCode}
            splitView={true}
            leftTitle="Original Code"
            rightTitle="AI Generated Fix"
        />
    );
};

export default DiffView;

DetailedFix.js

This component serves as the main container for displaying issue details and orchestrates the visibility of the "Diff View" tab.

  • Dynamic Tab Management: The list of navigation tabs (navs) is dynamically generated using a React.useMemo hook. The "Diff View" tab is conditionally added to this list only when an AI solution is present in the Redux store.
  • Automatic Tab Switching: A useEffect hook monitors the aiSolution state. When a new solution is generated and populated in the store, this hook automatically sets "Diff View" as the active tab, bringing the changes to the user's immediate attention.
  • State Propagation: It retrieves the sourceSnippet (original code) and aiSolution (which contains the new code) from the Redux store and passes them as props to the DiffView component.

File: main/js/sec_ai/components/Navigations/DetailedFix.js

// ... (imports)

function DetailedFix({ jumpTarget, clearJumpTarget }) {
    // ... (state and selectors)
    const sourceSnippet = useSelector(selectSourceCode);
    const aiSolution = useSelector(selectAiSolution);
    const [selectedTab, setSelectedTab] = useState('Root Cause');

    const navs = React.useMemo(() => {
        // ... (logic to build base tab list)
        if (aiSolution && aiSolution.Final_Secure_Code_Snippet) {
            list.push('Diff View');
        }
        return list;
    }, [selectedIssue, aiSolution]);

    useEffect(() => {
        if (aiSolution && aiSolution.Final_Secure_Code_Snippet) {
            setSelectedTab('Diff View');
        }
    }, [aiSolution]);

    // ... (render logic)
    {selectedTab === "Diff View" && (
        <DiffView
            oldCode={sourceSnippet}
            newCode={aiSolution?.Final_Secure_Code_Snippet}
        />
    )}
    // ...
}

2.2. State Management (Redux)

The issuesReducer.js manages the state required for the Diff View to function.

  • aiSolution State: When a user generates an AI fix in the AiFix.js component, the resulting JSON object, which includes the Final_Secure_Code_Snippet, is dispatched and stored in the aiSolution slice of the Redux state.
  • sourceCode State: The original code snippet associated with a selected issue is stored in the sourceCode slice. This is populated when a user clicks on an issue from the list.
  • Selectors: The selectAiSolution and selectSourceCode selectors are used by DetailedFix.js to retrieve the necessary data from the store.

3. User Flow

  1. A user selects a vulnerability from the issue list in the main view.
  2. The application fetches the issue details, including the original code snippet (sourceSnippet), and stores it in the Redux store.
  3. The user navigates to the "AI Fix" tab and clicks the "Generate the fix" button.
  4. The AiFix.js component sends a request to the backend. Upon receiving a successful response, it dispatches the setAiSolution action to update the Redux store with the AI-generated fix.
  5. The useEffect hook in DetailedFix.js detects the change in the aiSolution state.
  6. The component automatically switches the active tab to "Diff View".
  7. The DiffView component renders, receiving the original code from sourceSnippet and the new code from aiSolution.Final_Secure_Code_Snippet, displaying them side-by-side.

4. Dependencies

  • react-diff-viewer-continued: A React component for displaying text diffs. This is a new dependency added to support this feature.