Skip to content

Add Blackhorse K-Graph cybersecurity dashboard frontend#20

Draft
Igor Holt (igor-holt) wants to merge 1 commit into
mainfrom
codex/implement-blackhorse-kgraph-dashboard
Draft

Add Blackhorse K-Graph cybersecurity dashboard frontend#20
Igor Holt (igor-holt) wants to merge 1 commit into
mainfrom
codex/implement-blackhorse-kgraph-dashboard

Conversation

@igor-holt
Copy link
Copy Markdown
Member

Motivation

  • Provide a modern React + TypeScript real-time dashboard to visualize Blackhorse threat streams and ʞ-Graph extractions for the CVE analysis platform.
  • Expose interactive operator controls (glass-break emergency trigger and modality escalation) alongside modality and sovereignty telemetry for faster incident response.
  • Deliver a styled, responsive UI component that can be integrated into an existing Vite/React app scaffold.

Description

  • Added frontend/BlackhorseKGraph.tsx, a React 19 + TypeScript component that defines typed models, opens a Socket.IO connection to ws://localhost:8080, subscribes to threat_stream, kg_extractions, and modality_telemetry, renders Cytoscape knowledge-graph elements, and draws Recharts time-series for cost/threat trends.
  • Added frontend/BlackhorseKGraph.module.css, a CSS module implementing the cyber-ops theme, layout, responsive rules, animations, and styles for all dashboard panels and controls.
  • Implemented client-side logic for knowledge-node styling, temporal edge heuristics, cost trajectory computation, and handlers that emit emergency and modality_request events back to the mesh.

Testing

  • Ran git diff --check and repository status checks with no reported issues.
  • Attempted an automated Playwright screenshot of http://127.0.0.1:5173, which failed with ERR_EMPTY_RESPONSE because no frontend dev server was running in this environment.
  • No unit tests were added in this PR; the component is standalone and should be integrated into a Vite/React app for full runtime and integration testing.

Codex Task

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello Igor Holt (@igor-holt), 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 delivers a new, modern React and TypeScript-based frontend dashboard designed to provide real-time visualization and interactive control for the Blackhorse threat intelligence platform. It integrates various data streams, including threat events, knowledge graph extractions, and AI model telemetry, to offer a comprehensive operational view for cybersecurity incident response and management.

Highlights

  • New Frontend Dashboard Component: Developed a new React 19 + TypeScript frontend component (BlackhorseKGraph.tsx) for the Blackhorse K-Graph cybersecurity dashboard, designed for real-time visualization and interaction.
  • Real-time Data Visualization: Implemented real-time data visualization using Socket.IO to subscribe to threat streams, k-Graph extractions, and modality telemetry, displayed via Cytoscape for knowledge graphs and Recharts for time-series data.
  • Interactive Operator Controls: Introduced interactive operator controls, including a 'glass-break' emergency trigger and modality escalation functionality, complete with corresponding UI elements and client-side logic.
  • Cyber-Ops Themed Styling: Created a dedicated CSS module (BlackhorseKGraph.module.css) to style the dashboard with a dark, cyber-operations theme, incorporating responsive design and animations.
Changelog
  • frontend/BlackhorseKGraph.module.css
    • Defined styles for the main dashboard layout, header, and navigation tabs.
    • Implemented visual indicators for status (thermal, sovereignty) and interactive buttons (glass break, escalate).
    • Styled various data display components like stat cards, threat lists, and model distribution bars.
    • Included responsive design rules for mobile devices.
  • frontend/BlackhorseKGraph.tsx
    • Created the BlackhorseKGraphDashboard React functional component.
    • Integrated socket.io-client for real-time data subscription to threat_stream, kg_extractions, and modality_telemetry.
    • Managed state for threats, knowledge nodes, modality, and sovereignty status.
    • Rendered interactive knowledge graphs using react-cytoscapejs with dynamic node and edge styling based on data properties.
    • Displayed time-series data for cost and threat trends using recharts.
    • Implemented callback functions for 'glass break' emergency and modality escalation events.
    • Structured the UI with tab-based navigation for different dashboard views (threats, knowledge, modality, sovereignty).
Activity
  • The author performed git diff --check and repository status checks, reporting no issues.
  • An automated Playwright screenshot attempt failed because no frontend development server was running in the test environment.
  • No unit tests were added, with the rationale that the component is standalone and requires integration into a Vite/React app for full runtime and integration testing.
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 (@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 (@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.

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

Code Review

The pull request introduces a new React and TypeScript frontend for the Blackhorse K-Graph cybersecurity dashboard, along with its associated CSS module. The dashboard visualizes threat streams, knowledge graph extractions, and modality telemetry. While the implementation provides a functional UI, several areas could be improved for maintainability, robustness, and clarity, particularly regarding hardcoded values, logging practices for critical events, and data representation logic.


// Initialize WebSocket connection to Blackhorse/ʞGraph bridge
useEffect(() => {
const newSocket = io('ws://localhost:8080', {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The WebSocket URL ws://localhost:8080 is hardcoded. This makes the component difficult to deploy in different environments (e.g., development, staging, production) without code changes. It should be configurable, perhaps via environment variables or a configuration file.

Suggested change
const newSocket = io('ws://localhost:8080', {
const newSocket = io(process.env.REACT_APP_WEBSOCKET_URL || 'ws://localhost:8080', {

Comment on lines +95 to +97
if (status.status !== 'SELF_DETERMINING') {
console.warn('[GLASS_BREAK] Sovereignty compromised');
}
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-high high

Using console.warn for a "Sovereignty compromised" event is not sufficient for a critical security alert. In a production system, such an event should trigger a more robust alerting mechanism (e.g., sending to a dedicated logging service, triggering an incident response workflow, or displaying a prominent, persistent warning in the UI) rather than just a console message.

font-weight: 600;
}

.statusIndicator.normal {
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

Hardcoded color values like #22c55e are used throughout the CSS. For better maintainability and easier theme management, consider defining these colors as CSS variables (custom properties) at a global or component level. This allows for centralized changes and promotes consistency.

  background: var(--color-success-light-alpha); /* Example: using a CSS variable */

});

newSocket.on('threat_event', (event: ThreatEvent) => {
setThreats(prev => [event, ...prev].slice(0, 100));
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

The threats array is limited to the latest 100 events using .slice(0, 100). While this might be an intentional performance optimization for a real-time dashboard, it's an arbitrary limit. Consider making this limit configurable or clearly documenting its purpose, especially if a more extensive history might be needed in the future. The same applies to knowledgeNodes on line 86.

Suggested change
setThreats(prev => [event, ...prev].slice(0, 100));
setThreats(prev => [event, ...prev].slice(0, MAX_THREAT_HISTORY));

Comment on lines +132 to +134
for (let j = i + 1; j < Math.min(i + 5, knowledgeNodes.length); j++) {
const timeDiff = Math.abs(knowledgeNodes[i].timestamp - knowledgeNodes[j].timestamp);
if (timeDiff < 60000) {
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

The values 5 (for Math.min(i + 5, knowledgeNodes.length)) and 60000 (for timeDiff < 60000) are magic numbers. These represent arbitrary thresholds for edge generation based on array index proximity and temporal difference. Extracting these into named constants would significantly improve readability and make the logic easier to understand and modify.

    const MAX_NODE_PROXIMITY = 5;
    const MAX_TIME_DIFF_MS = 60000; // 1 minute
    for (let i = 0; i < knowledgeNodes.length - 1; i++) {
      for (let j = i + 1; j < Math.min(i + MAX_NODE_PROXIMITY, knowledgeNodes.length); j++) {
        const timeDiff = Math.abs(knowledgeNodes[i].timestamp - knowledgeNodes[j].timestamp);
        if (timeDiff < MAX_TIME_DIFF_MS) {

Comment on lines +183 to +184
time: new Date(t.timestamp).toLocaleTimeString(),
cost: (modality.cost_this_session * (i + 1)) / 20,
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

The calculation (modality.cost_this_session * (i + 1)) / 20 for the cost in costData appears to be an arbitrary scaling of the current session cost. If the intention is to show a historical cost trajectory, this calculation might be misleading as it doesn't reflect actual past costs. Consider if there's a more accurate way to derive or simulate historical cost data for the chart, or clarify the intent of this calculation.

Comment on lines +201 to +205
modality.current_model === 'Haiku'
? 'Sonnet'
: modality.current_model === 'Sonnet'
? 'Opus'
: 'Haiku',
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

The nested ternary operator for determining the target model in requestModalityEscalation is difficult to read and maintain. For better clarity and extensibility, consider using a switch statement or a lookup map to define the escalation logic.

      socket.emit('modality_request', {
        target: (() => {
          switch (modality.current_model) {
            case 'Haiku': return 'Sonnet';
            case 'Sonnet': return 'Opus';
            case 'Opus': return 'Haiku';
            default: return 'Haiku'; // Fallback
          }
        })(),
        reason: 'Manual override from dashboard'
      });

<div className={styles.titleSection}>
<Shield className={styles.logoIcon} size={32} />
<h1>BLACKHORSE // ʞ GRAPH</h1>
<span className={styles.version}>v4.20-DELTA</span>
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

The version string v4.20-DELTA is hardcoded directly in the component. For better release management and consistency, this version should ideally be dynamically loaded from a package.json file or an environment variable during the build process.

          <span className={styles.version}>{process.env.REACT_APP_VERSION || 'N/A'}</span>

<div className={`${styles.statusLarge} ${styles[sovereignty.status.toLowerCase()]}`}>
<Shield size={64} />
<h2>{sovereignty.status}</h2>
<p>Last Verified: {new Date(sovereignty.last_check).toLocaleString()}</p>
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

Using toLocaleString() without specifying a locale or options can lead to inconsistent date and time formatting across different user environments. For a dashboard, it's generally better to enforce a consistent format. Consider providing specific locale and options (e.g., new Date(sovereignty.last_check).toLocaleString('en-US', { dateStyle: 'medium', timeStyle: 'short' })) to ensure uniform display.

                <p>Last Verified: {new Date(sovereignty.last_check).toLocaleString('en-US', { dateStyle: 'medium', timeStyle: 'short' })}</p>

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant