Skip to content

Conversation

@NiveditJain
Copy link
Member

No description provided.

…functionality

- Removed the `get_current_states` and `get_states_by_run_id` controllers, streamlining the API to focus on runs.
- Introduced a new `get_runs` controller to fetch run data, updating the corresponding route to reflect this change.
- Updated response models to accommodate the new runs structure, enhancing the overall state management architecture.
- Updated the `errored_state` function to differentiate between retry states and errored states, setting the status to `RETRY_CREATED` when a retry state is created, and `ERRORED` otherwise.
- Introduced a new `RETRY_CREATED` status in the `StateStatusEnum` to support the updated logic.
- Modified the `check_unites_satisfied` function to exclude `RETRY_CREATED` from the success criteria, improving state validation logic.
- Introduced a new `Run` model to represent execution runs, including fields for run ID, graph name, namespace name, and creation timestamp.
- Updated the `get_runs` controller to fetch and return run data, integrating run status and counts for various state categories.
- Enhanced the `trigger_graph` function to create and insert new run records upon triggering a graph execution.
- Added a new `RunStatusEnum` to manage the status of runs, improving clarity in run state management.
- Refactored response models to accommodate the new run structure, streamlining the overall state management architecture.
- Updated imports in `routes.py` and `get_runs.py` to reference the newly created `run_models` instead of the deprecated `state_list_models`.
- Modified the `trigger_graph` function to remove the status assignment, streamlining the run creation process.
- Introduced `run_models.py` to define response models for run management, including `RunStatusEnum`, `RunListItem`, and `RunsResponse`, enhancing clarity and structure in handling run data.
…documentation

- Changed the tags for `list_graph_templates_route` and `get_graph_structure_route` from "state" to "runs" to better reflect their functionality related to run management.
- Updated environment configuration to separate server-side and client-side variables, ensuring sensitive information like API keys are not exposed to the client.
- Introduced a new `clientApiService` to handle API calls through server-side routes, improving security by keeping API keys on the server.
- Refactored components to utilize the new client API service, removing direct API key handling from the client-side code.
- Added new API routes for fetching graph structures, graph templates, namespace overviews, and runs, streamlining data retrieval processes.
- Documented the security architecture and best practices for environment variable management in a new SECURITY.md file.
- Updated environment variables to separate server-side and client-side configurations, ensuring sensitive information like API keys are securely handled.
- Introduced `EXOSPHERE_STATE_MANAGER_URI` and `EXOSPHERE_API_KEY` for server-side use, replacing previous variables.
- Enhanced documentation to reflect the new security architecture, emphasizing server-side rendering (SSR) and the protection of sensitive credentials.
- Updated API routes to utilize the new environment variables, ensuring secure communication with the state manager.
- Improved Docker Compose setup and documentation for clarity and security best practices.
…omponents

- Added new API endpoints for retrieving runs and graph structures, improving data access for users.
- Refactored the dashboard components to utilize the updated API structure, including renaming tabs for clarity.
- Removed the `StatesByRunId` component and associated state management logic to streamline the application.
- Updated documentation to reflect the new API endpoints and changes in the dashboard structure.
- Modified the `get_run_status` function to check for both `ERRORED` and `NEXT_CREATED_ERROR` states, improving error handling in run status determination.
… structure

- Removed unused properties from GraphNode and GraphEdge interfaces, streamlining the data structure.
- Updated GraphVisualization component to display more relevant node information, including ID, name, and status.
- Adjusted edge ID generation for consistency and clarity in the graph representation.
- Enhanced the overall organization of the GraphVisualization component for better readability.
- Removed unused imports and properties in `graph_structure_models.py` for cleaner code.
- Updated test cases in `test_main.py` to include the new `Run` model in expected outputs.
- Adjusted route tags in `test_routes.py` to reflect the addition of run-related functionality.
- Introduced comprehensive tests for CORS configuration in `test_cors.py`, ensuring proper handling of environment variables.
- Streamlined tests for current states and run management, improving overall test coverage and clarity.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • New Runs table with pagination, per-run status/progress, and one-click graph visualization.
    • Consolidated Namespace Overview data.
    • Server-side routes for runs, graph structure, namespace overview, and graph templates.
  • Refactor

    • Secure SSR architecture: API key handled server-side; public URL replaced with private URI; UI no longer asks for an API key.
    • Updated environment variables, including a default namespace.
  • Documentation

    • Overhauled guides for security architecture, environment setup, and Docker usage.
  • Tests

    • Added coverage for runs, CORS, retry policy; removed obsolete state-list tests.

Walkthrough

Reworked the dashboard to route all state-manager calls server-side via new Next.js API routes, introduced server-side environment variables EXOSPHERE_STATE_MANAGER_URI and EXOSPHERE_API_KEY, replaced states-centric APIs/UI with runs-centric models/endpoints, added Run persistence and run-list controllers in the state-manager, simplified graph models, and updated documentation and tests accordingly.

Changes

Cohort / File(s) Summary
Docker & Compose / Env examples
dashboard/Dockerfile, dashboard/env.example, docker-compose/docker-compose*.yml, docker-compose/README.md
Removed client-exposed NEXT_PUBLIC state-manager URL and dev API key; added server-side EXOSPHERE_STATE_MANAGER_URI and EXOSPHERE_API_KEY; added NEXT_PUBLIC_DEFAULT_NAMESPACE; updated docs and Docker run examples to use server-side variables.
Dashboard server API routes
dashboard/src/app/api/*/route.ts
.../runs/route.ts, .../graph-structure/route.ts, .../namespace-overview/route.ts, .../graph-template/route.ts
New Next.js App Router server handlers that proxy requests to the state-manager using EXOSPHERE_STATE_MANAGER_URI and EXOSPHERE_API_KEY, perform validation, and return JSON or errors.
Client-side API wrapper
dashboard/src/services/clientApi.ts
New clientApiService that calls the dashboard API routes (GET/PUT for runs, graph-structure, namespace-overview, graph-template) and handles response.ok checks.
Legacy service refactor
dashboard/src/services/api.ts
Removed current-states APIs; adjusted server URL env key name; added run- and graph-oriented methods (getRuns, getGraphStructure).
UI: components added/updated/removed
dashboard/src/components/RunsTable.tsx, dashboard/src/components/GraphVisualization.tsx, dashboard/src/components/NamespaceOverview.tsx, dashboard/src/components/StatesByRunId.tsx
Added RunsTable; GraphVisualization & NamespaceOverview switched to clientApiService and dropped apiKey props; removed StatesByRunId component.
App page
dashboard/src/app/page.tsx
Replaced states view with RunsTable, removed API key UI/state, migrated calls to clientApiService, use NEXT_PUBLIC_DEFAULT_NAMESPACE fallback.
Types (dashboard)
dashboard/src/types/state-manager.ts
Removed CurrentStates/StatesByRunId types; simplified GraphNode/GraphEdge/GraphStructureResponse; added RunStatusEnum, RunListItem, RunsResponse.
Docs
dashboard/README.md, dashboard/SECURITY.md, docs/docs/*
Added Security Architecture, SSR notes, server-side env variable docs, API route docs, updated quick start, docker and compose docs to reflect server-side API key flow and namespace variable.
State-manager: models & DB
state-manager/app/models/db/run.py, .../run_models.py, .../graph_structure_models.py, .../state_list_models.py (removed), .../state_status_enum.py
Added Run document and run response models; simplified graph structure models (removed timestamps/inputs/outputs/edge ids, added summary metrics); removed state_list_models; added RETRY_CREATED, removed CANCELLED.
State-manager: controllers & routes
state-manager/app/controller/get_runs.py, updated get_graph_structure.py, trigger_graph.py, errored_state.py, removed get_current_states.py, get_states_by_run_id.py, updated app/routes.py, app/main.py
New get_runs controller and runs endpoints; graph structure output adjusted; trigger_graph now persists Run; errored flow reports/marks retry creation; Beanie registration updated to include Run; routes retagged from state->runs.
Tasks & logic updates
state-manager/app/tasks/create_next_states.py
Adjusted ALL_SUCCESS predicate to treat RETRY_CREATED as satisfied using NotIn semantics.
Tests
state-manager/tests/unit/...
Added/updated tests: runs controller tests, CORS tests, retry policy tests; removed or reduced tests for removed state-list controllers; updated graph-structure and route tests to match new models and behaviors.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User (Browser)
  participant C as Dashboard Client
  participant S as Next.js API Routes (server)
  participant M as State Manager

  U->>C: Request Runs view
  C->>S: GET /api/runs?namespace=...
  S->>S: Read EXOSPHERE_STATE_MANAGER_URI, EXOSPHERE_API_KEY
  S->>M: GET /v0/namespace/{ns}/runs/{page}/{size} with X-API-Key
  M-->>S: RunsResponse JSON
  S-->>C: RunsResponse
  C-->>U: Render RunsTable
Loading
sequenceDiagram
  autonumber
  actor U as User (Browser)
  participant C as Dashboard Client
  participant S as Next.js API Routes (server)
  participant M as State Manager

  U->>C: Save Graph Template
  C->>S: PUT /api/graph-template?namespace=...&graphName=... (body)
  S->>S: Validate params & server API key presence
  S->>M: PUT /v0/namespace/{ns}/graph/{graphName} with X-API-Key and body
  alt Upstream OK
    M-->>S: 200 JSON
    S-->>C: 200 JSON
  else Error
    M-->>S: Error
    S-->>C: 500 { error }
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • nk-ag

Poem

A rabbit hops through code at night,
Tucks keys away—out of the light.
Runs gather neatly in tidy rows,
Server burrows hide what nobody knows.
Hooray for secure tunnels and no client fright! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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.

Summary of Changes

Hello @NiveditJain, 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 focuses on a major security and usability upgrade for the dashboard. By migrating API key handling to the server-side via Next.js API routes, it significantly hardens the application's security posture. Concurrently, it introduces a more intuitive and feature-rich 'Runs' overview, allowing users to better monitor and understand their workflow executions. The changes span both frontend and backend components, along with comprehensive documentation updates, to ensure a seamless and secure experience.

Highlights

  • Enhanced Dashboard Security: The dashboard has been refactored to utilize Server-Side Rendering (SSR) and Next.js API routes. This significant change ensures that sensitive information, such as API keys, is handled server-side and is never exposed to the client-side browser, greatly improving security.
  • Improved Workflow Monitoring: A new 'Runs' table has been introduced in the dashboard, replacing the previous 'States by Run ID' view. This new table provides a comprehensive overview of workflow executions, including status, progress, and detailed state counts, along with the ability to visualize the graph structure for each run.
  • Standardized Environment Configuration: Environment variables across the dashboard and Docker Compose setups have been updated and standardized. This includes new variables like 'EXOSPHERE_STATE_MANAGER_URI' and 'EXOSPHERE_API_KEY' for server-side configuration, ensuring clear separation between public and sensitive settings.
  • Comprehensive Documentation Updates: Extensive updates have been made to the 'README.md' files and official documentation to reflect the new security architecture, environment variable usage, and the enhanced workflow monitoring features, providing clear guidance for users and developers.
  • State Manager Backend Alignment: The state manager backend has been updated to align with the new dashboard features, including the introduction of a 'Run' database model to track workflow executions, new API endpoints for fetching runs and graph structures, and refinements to state status handling.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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.

- Introduced project root path to `sys.path` in `test_cors.py` to ensure proper module resolution during tests.
- Updated imports to maintain compatibility with the new project structure.
Copy link
Contributor

@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

This pull request introduces a significant and important security refactoring for the dashboard by moving API calls to server-side Next.js routes, preventing API key exposure on the client. The introduction of a new SECURITY.md and updates to documentation are excellent additions. The backend is also updated with a new /runs endpoint to support the new dashboard view, which is a great improvement for monitoring.

My review focuses on a few critical areas. I've identified a security issue with a hardcoded default API key in the Dockerfile and a major performance bottleneck (N+1 query problem) in the new /runs endpoint controller. I've also included a couple of medium-severity suggestions to improve code maintainability and robustness on the frontend. Addressing these points will help ensure the new architecture is both secure and scalable.

@codecov
Copy link

codecov bot commented Sep 2, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

- Added a ruff directive to `test_cors.py` to suppress the E402 error, allowing imports to be placed after code statements for improved organization.
- This change enhances code readability while maintaining functionality in the test setup.
@NiveditJain
Copy link
Member Author

@coderabbitai review this pr

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

@NiveditJain I'll review PR #335 for the dashboard fixes right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai bot added the enhancement New feature or request label Sep 2, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 84

Caution

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

⚠️ Outside diff range comments (25)
dashboard/src/services/api.ts (2)

23-42: Add timeout, no-store caching, and richer error messages to fetch.

Avoid indefinite hangs and surface server error bodies.

-class ApiService {
-  private async makeRequest<T>(
-    endpoint: string,
-    options: RequestInit = {}
-  ): Promise<T> {
+class ApiService {
+  private async makeRequest<T>(
+    endpoint: string,
+    options: RequestInit = {},
+    timeoutMs: number = 10_000
+  ): Promise<T> {
     const url = `${API_BASE_URL}${endpoint}`;
-    
-    const response = await fetch(url, {
-      headers: {
-        'Content-Type': 'application/json',
-        ...options.headers,
-      },
-      ...options,
-    });
-
-    if (!response.ok) {
-      throw new Error(`API request failed: ${response.status} ${response.statusText}`);
-    }
-
-    return response.json();
+    const controller = new AbortController();
+    const timer = setTimeout(() => controller.abort(), timeoutMs);
+    try {
+      const response = await fetch(url, {
+        ...options,
+        headers: {
+          'Content-Type': 'application/json',
+          ...options.headers,
+        },
+        cache: 'no-store',
+        signal: controller.signal,
+      });
+      if (!response.ok) {
+        const body = await response.text().catch(() => '');
+        throw new Error(`API request failed: ${response.status} ${response.statusText}${body ? ` - ${body}` : ''}`);
+      }
+      return response.json();
+    } finally {
+      clearTimeout(timer);
+    }
   }

216-232: Document runs endpoint pagination and ordering
The route /v0/namespace/{namespace_name}/runs/{page}/{size} is correct; results are sorted by created_at descending, page is 1-indexed and defaults to 1 (with a default size of 20). Add these semantics to the API docs.

state-manager/app/models/graph_structure_models.py (1)

14-17: Add optional source_output and target_input fields to GraphEdge
Dropping these fields loses port/channel info and makes parallel edges indistinguishable.

 class GraphEdge(BaseModel):
     source: str = Field(..., description="Source node ID")
     target: str = Field(..., description="Target node ID")
+    source_output: Optional[str] = Field(None, description="Source output port (if applicable)")
+    target_input: Optional[str] = Field(None, description="Target input port (if applicable)")

If parallel edges are impossible by design, annotate that invariant in GraphEdge.

state-manager/app/tasks/create_next_states.py (4)

63-76: Bug: validate_dependencies rejects 'store' placeholders

This raises KeyError for valid store references. Skip ‘store’ in the parents check.

         for dependent in dependency_string.dependents.values():
             # 2) For each placeholder, verify the identifier is either current or present in parents
-            if dependent.identifier != identifier and dependent.identifier not in parents:
+            if dependent.identifier == "store":
+                # store-backed values are validated when resolving via get_store_value
+                continue
+            if dependent.identifier != identifier and dependent.identifier not in parents:
                 raise KeyError(f"Identifier '{dependent.identifier}' not found in parents for template '{next_state_node_template.identifier}'")

124-136: Store value type may be non-string; relax typing

Store/default values may be non-str. Broaden typing to Any to match inputs schema flexibility.

-        async def get_store_value(run_id: str, field: str) -> str:
+        async def get_store_value(run_id: str, field: str) -> Any:
             key = (run_id, field)
             if key not in cached_store_values:
                 store_value = await Store.get_value(run_id, namespace, graph_name, field)
@@
-                cached_store_values[key] = store_value
+                cached_store_values[key] = store_value
             return cached_store_values[key]

231-239: Log with stack trace on duplicate insert race

Capture traceback to aid diagnosis; warning without trace hampers debugging.

-        except (DuplicateKeyError, BulkWriteError):
-            logger.warning(
+        except (DuplicateKeyError, BulkWriteError):
+            logger.warning(
                 f"Caught duplicate key error for new unit states in namespace={namespace}, "
                 f"graph={graph_name}, likely due to a race condition. "
-                f"Attempted to insert {len(new_unit_states_coroutines)} states"
-            )
+                f"Attempted to insert {len(new_unit_states_coroutines)} states",
+                exc_info=True,
+            )

48-56: Include RETRY_CREATED in ALL_DONE pending statuses
In state-manager/app/tasks/create_next_states.py’s ALL_DONE branch, extend the In(...) filter to block on retries:

-    In(State.status, [StateStatusEnum.CREATED, StateStatusEnum.QUEUED, StateStatusEnum.EXECUTED]),
+    In(State.status, [StateStatusEnum.CREATED, StateStatusEnum.QUEUED, StateStatusEnum.EXECUTED, StateStatusEnum.RETRY_CREATED]),
state-manager/tests/unit/controller/test_trigger_graph.py (1)

49-51: Optionally assert Run was constructed

Strengthen the contract that a Run record is created.

-        assert isinstance(result.run_id, str) and len(result.run_id) > 0
+        assert isinstance(result.run_id, str) and len(result.run_id) > 0
+        mock_run_cls.assert_called_once()
state-manager/tests/unit/controller/test_get_graph_structure.py (1)

266-297: Include new statuses (PRUNED, RETRY_CREATED) in coverage.

The enum gained RETRY_CREATED and treats PRUNED as success; ensure execution_summary and root_states logic cover them.

Apply:

-        statuses = [StateStatusEnum.CREATED, StateStatusEnum.QUEUED, StateStatusEnum.EXECUTED, 
-                   StateStatusEnum.SUCCESS, StateStatusEnum.ERRORED, StateStatusEnum.NEXT_CREATED_ERROR]
+        statuses = [
+            StateStatusEnum.CREATED,
+            StateStatusEnum.QUEUED,
+            StateStatusEnum.EXECUTED,
+            StateStatusEnum.SUCCESS,
+            StateStatusEnum.PRUNED,
+            StateStatusEnum.ERRORED,
+            StateStatusEnum.NEXT_CREATED_ERROR,
+            StateStatusEnum.RETRY_CREATED,
+        ]

And update expected counts accordingly if assertions depend on length.

dashboard/Dockerfile (2)

13-13: Drop unused build dependency or at least clean APT cache.

If openssl isn’t required during build, remove it. If required, clean APT lists to keep layers slim.

Option A (remove):

-RUN apt-get update && apt-get install -y --no-install-recommends openssl

Option B (keep + clean):

-RUN apt-get update && apt-get install -y --no-install-recommends openssl
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends openssl \
+ && rm -rf /var/lib/apt/lists/*

31-33: Fix misleading comment about HOSTNAME.

0.0.0.0 binds all interfaces, not “localhost”.

-# set hostname to localhost
+# bind to all interfaces
 ENV HOSTNAME=0.0.0.0
dashboard/src/components/NamespaceOverview.tsx (4)

133-137: Avoid using array index as React key for nodes.

Use a stable identifier (e.g., node.id or node.name) to prevent subtle UI bugs on re-ordering.

Apply this diff:

-                {nodesResponse.nodes.map((node, index) => (
-                  <div 
-                    key={index} 
+                {nodesResponse.nodes.map((node) => (
+                  <div 
+                    key={node.id ?? node.name} 

184-186: Avoid using array index as React key for templates.

Prefer template.id or template.name for stability.

-                {templatesResponse.templates.map((template, index) => (
-                  <div key={index} className="border border-gray-200 rounded-lg p-4">
+                {templatesResponse.templates.map((template) => (
+                  <div key={template.id ?? template.name} className="border border-gray-200 rounded-lg p-4">

139-144: Defensive access for secrets length.

node.secrets may be undefined; guard to avoid runtime errors.

-                      <span className="text-xs bg-[#031035]/10 text-[#031035] px-2 py-1 rounded">
-                        {node.secrets.length} secrets
-                      </span>
+                      <span className="text-xs bg-[#031035]/10 text-[#031035] px-2 py-1 rounded">
+                        {(node.secrets?.length ?? 0)} secrets
+                      </span>

89-96: Add explicit button type for a11y and to avoid accidental form submit.

Set type="button" on non-submit buttons.

-            <button type="button"
+            <button type="button"
               onClick={loadNamespaceData}
               className="mt-3 inline-flex items-center px-3 py-1 border border-transparent text-sm font-medium rounded-md text-red-700 bg-red-100 hover:bg-red-200"
             >
-        <button
+        <button type="button"
           onClick={loadNamespaceData}
           className="flex items-center space-x-2 px-4 py-2 bg-[#031035] text-white rounded-lg hover:bg-[#0a1a4a] transition-colors"
         >
-                          <button
-                            type="button"
+                          <button
+                            type="button"
                             onClick={(e) => {
                               e.stopPropagation();
                               // For now, we'll use a generic name since we don't have the actual graph name
                               onOpenGraphTemplate(template.name);
                             }}
                             className="text-xs bg-[#031035] text-white px-2 py-1 rounded hover:bg-[#0a1a4a] transition-colors"
                           >

Also applies to: 107-112, 218-229

docker-compose/docker-compose-with-mongodb.yml (2)

29-29: MongoDB auth likely fails without authSource=admin.

When creating the root user via MONGO_INITDB_ROOT_USERNAME, clients must authenticate against the admin DB. Add authSource to the URI.

-      - MONGO_URI=${MONGO_URI:-mongodb://admin:password@exosphere-mongodb:27017/}
+      - MONGO_URI=${MONGO_URI:-mongodb://admin:password@exosphere-mongodb:27017/?authSource=admin}

37-37: Optional: avoid exposing state-manager on host by default.

If dashboard proxies all access, you can drop or restrict "8000:8000" to 127.0.0.1 to reduce attack surface.

-      - "8000:8000"
+      # - "127.0.0.1:8000:8000"  # or remove entirely if not needed outside the network
dashboard/src/components/GraphVisualization.tsx (2)

246-246: Make node connectability consistent with canvas settings.

nodesConnectable is false, but each node sets connectable: true. Align to false to avoid surprises.

-          connectable: true,
+          connectable: false,

305-311: Add explicit button type for a11y.

Set type="button" on non-submit buttons.

-            <button
+            <button type="button"
               onClick={loadGraphStructure}
-         <button
+         <button type="button"
            onClick={loadGraphStructure}
-              <button
+              <button type="button"
                 onClick={() => setSelectedNode(null)}

Also applies to: 340-345, 406-410

state-manager/app/controller/get_graph_structure.py (3)

76-78: Guard against parents being None.

len(state.parents) will raise when parents is None. Use truthiness checks instead.

-            if len(state.parents) == 0:
+            if not state.parents:
                 root_states.append(state_id_to_node[str(state.id)])
                 continue        

66-67: Remove unused counter.

edge_id_counter is never used.

-        edge_id_counter = 0

80-96: Confirm “most recent parent only” is intended.

You now emit a single edge to the last-added parent, dropping other direct parents (fan-in). If graphs can have joins, this loses structure. If intentional, consider documenting; if not, iterate all direct parents.

Example to include all direct parents:

-            if state.parents:
-                parent_items = list(state.parents.items())
-                if parent_items:                    
-                    _ , parent_id = parent_items[-1]                                   
-                    parent_id_str = str(parent_id)
-                    if parent_id_str in state_id_to_node:
-                        edge = GraphEdge(
-                            source=parent_id_str,
-                            target=state_id,
-                        )
-                        edges.append(edge)
+            if state.parents:
+                for _, parent_id in state.parents.items():
+                    parent_id_str = str(parent_id)
+                    if parent_id_str in state_id_to_node:
+                        edges.append(GraphEdge(source=parent_id_str, target=state_id))
dashboard/src/app/page.tsx (2)

37-44: Add loading and error-reset around save to avoid stale UI state

Currently save doesn’t clear prior errors or show the "Processing..." indicator; only the modal fetch toggles isLoading.

Apply:

 const handleSaveGraphTemplate = async (template: UpsertGraphTemplateRequest) => {
-  try {
-    await clientApiService.upsertGraphTemplate(namespace, graphName, template);
-    setGraphTemplate(template);
-  } catch (err) {
-    setError(err instanceof Error ? err.message : 'Failed to save graph template');
-  }
+  setError(null);
+  setIsLoading(true);
+  try {
+    await clientApiService.upsertGraphTemplate(namespace, graphName, template);
+    setGraphTemplate(template);
+  } catch (err) {
+    setError(err instanceof Error ? err.message : 'Failed to save graph template');
+  } finally {
+    setIsLoading(false);
+  }
 };

96-103: Improve header input accessibility/contrast

On a dark header, gray border may be low-contrast and there’s no label association. Add aria-label and boost focus/contrast.

-<input
+<input
   type="text"
   value={namespace}
   onChange={(e) => setNamespace(e.target.value)}
-  className="px-2 py-1 text-sm text-white border border-gray-300 rounded"
+  aria-label="Namespace"
+  placeholder="Namespace"
+  className="px-2 py-1 text-sm text-white bg-transparent border border-white/30 rounded placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-white/50"
 />
docs/docs/exosphere/dashboard.md (1)

100-104: Fix env filename for Next.js local dev

Next.js expects .env.local (not .env) by default. The text and command should match.

- cp .env.example .env
- # Edit .env with your configuration
+ cp .env.example .env.local
+ # Edit .env.local with your configuration
♻️ Duplicate comments (3)
state-manager/app/controller/get_runs.py (1)

20-31: Severe N+1 query pattern and 5× count() per run; aggregate per page.

Each run triggers multiple count() calls; for page size N this explodes to O(N) roundtrips and is already flagged previously. Replace per-run counts with a single aggregation pipeline grouped by run_id.

Illustrative refactor (1 DB call for the page):

-async def get_run_info(run: Run) -> RunListItem:
-    return RunListItem(
-        run_id=run.run_id,
-        graph_name=run.graph_name,
-        success_count=await State.find(State.run_id == run.run_id, In(State.status, [StateStatusEnum.SUCCESS, StateStatusEnum.PRUNED])).count(),
-        pending_count=await State.find(State.run_id == run.run_id, In(State.status, [StateStatusEnum.CREATED, StateStatusEnum.QUEUED, StateStatusEnum.EXECUTED])).count(),
-        errored_count=await State.find(State.run_id == run.run_id, In(State.status, [StateStatusEnum.ERRORED, StateStatusEnum.NEXT_CREATED_ERROR])).count(),
-        retried_count=await State.find(State.run_id == run.run_id, State.status == StateStatusEnum.RETRY_CREATED).count(),
-        total_count=await State.find(State.run_id == run.run_id,).count(),
-        status=await get_run_status(run.run_id),
-        created_at=run.created_at
-    )
+async def get_run_info(run: Run) -> RunListItem:
+    [doc] = await State.aggregate([
+        {"$match": {"run_id": run.run_id}},
+        {"$group": {
+            "_id": "$run_id",
+            "success_count": {"$sum": {"$cond": [{"$in": ["$status", ["SUCCESS","PRUNED"]]}, 1, 0]}},
+            "pending_count": {"$sum": {"$cond": [{"$in": ["$status", ["CREATED","QUEUED","EXECUTED"]]}, 1, 0]}},
+            "errored_count": {"$sum": {"$cond": [{"$in": ["$status", ["ERRORED","NEXT_CREATED_ERROR"]]}, 1, 0]}},
+            "retried_count": {"$sum": {"$cond": [{"$eq": ["$status", "RETRY_CREATED"]}, 1, 0]}},
+            "total_count": {"$sum": 1}
+        }}
+    ]).to_list() or [{"success_count":0,"pending_count":0,"errored_count":0,"retried_count":0,"total_count":0}]
+    status = await get_run_status(run.run_id)
+    return RunListItem(
+        run_id=run.run_id,
+        graph_name=run.graph_name,
+        created_at=run.created_at,
+        status=status,
+        **{k: int(doc.get(k, 0)) for k in ("success_count","pending_count","errored_count","retried_count","total_count")}
+    )

Page-level optimization (preferred): run a single pipeline with $match: {"run_id": {"$in": [...]}} and $group by run_id, then compute statuses in memory.

Add an index to support this hot path:

  • State: compound index on (namespace_name, run_id, status). This will accelerate the $match and conditional sums.
dashboard/Dockerfile (1)

42-44: Remove hardcoded API key from the image (secrets-in-image).

Baking EXOSPHERE_API_KEY into the Docker image leaks credentials via image layers. Require it at runtime via env/secret and fail fast if missing. This mirrors a prior review—still unresolved.

Apply:

-ENV EXOSPHERE_API_KEY=exosphere@123
dashboard/src/components/GraphVisualization.tsx (1)

253-255: Good fix: deterministic edge IDs.

Switching to edge-${source}-${target} resolves the prior key/index issue for edges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review continued from previous batch...

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review continued from previous batch...

…olation

- Clarified the description of environment variable isolation, specifying that server-side environment variables are set in containers and available to server processes, but not exposed to the browser/client bundle. This enhances understanding of security features in the Docker setup.
- Introduced new test cases for the `get_run_details_by_run_id_route`, covering scenarios for valid and invalid API keys, as well as service errors.
- Removed commented-out code for unused route handlers to improve code clarity.
- Enhanced test coverage for run-related functionality, ensuring proper validation and error handling.
- Changed the environment variable from `NEXT_PUBLIC_EXOSPHERE_STATE_MANAGER_URI` to `EXOSPHERE_STATE_MANAGER_URI` in `api.ts` to align with the updated security architecture and ensure proper server-side usage.
…e.md

- Clarified the authentication process by changing "checked for equality" to "compared to" for better accuracy.
- Ensured consistent formatting by adding a newline at the end of the file.
- Updated the errored_state function to ensure that a retry state is created even when a DuplicateKeyError occurs, improving the robustness of state management in error scenarios.
- Updated the assertion in `test_errored_state.py` to correctly check the status of `mock_state_queued` as `RETRY_CREATED`.
- Adjusted comments in `test_get_runs.py` for clarity, ensuring consistent formatting in the test setup.
- Introduced tests for `get_runs_route` and `get_graph_structure_route`, validating behavior with both valid and invalid API keys.
- Updated assertions to include new route checks and removed commented-out code for clarity.
- Enhanced overall test coverage for route handlers, ensuring robust validation and error handling.
- Refactored existing tests to improve clarity and structure, including the addition of comprehensive assertions for the response structure.
- Introduced a new test case to validate the response structure of the `get_run_details_by_run_id_route`, ensuring all fields are correctly returned.
- Removed commented-out code to streamline the test file and improve readability.
- Ensured robust validation for both valid and invalid API keys, as well as error handling for service exceptions.
- Enhanced the test suite for the `get_runs_route` by adding detailed mock responses and assertions to validate the response structure and content.
- Implemented tests for pagination scenarios, including edge cases for empty results and single-item responses.
- Added error handling tests to ensure proper behavior when the service raises exceptions.
- Removed the obsolete test file `test_get_current_states.py` to streamline the test suite.
- Removed unused imports of `RunListItem`, `RunStatusEnum`, and `RunsResponse` from the test cases in `TestRouteHandlerAPIKeyValidation`.
- Streamlined the test file to improve readability and maintainability.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 23

Caution

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

⚠️ Outside diff range comments (7)
state-manager/tests/unit/controller/test_errored_state.py (2)

103-106: Update expected response for the happy-path queued case

A successfully enqueued retry should surface as RETRY_CREATED with retry_created=True.

-        assert result.status == StateStatusEnum.ERRORED
+        assert result.status == StateStatusEnum.RETRY_CREATED
+        assert result.retry_created

308-312: Keep response consistent across variants

This path also creates a retry; assert RETRY_CREATED and the flag.

-        assert result.status == StateStatusEnum.ERRORED
+        assert result.status == StateStatusEnum.RETRY_CREATED
+        assert result.retry_created
         assert mock_state_class.find_one.call_count == 1  # Called once for finding
         assert mock_state_queued.error == "Different error message"
state-manager/app/controller/errored_state.py (1)

75-77: Polish log message phrasing

Minor: “Error errored state …” reads awkward. Prefer clearer wording.

-        logger.error(f"Error errored state {state_id} for namespace {namespace_name}", x_exosphere_request_id=x_exosphere_request_id, error=e)
+        logger.error(f"Error marking state {state_id} as errored for namespace {namespace_name}", x_exosphere_request_id=x_exosphere_request_id, error=e)
dashboard/src/services/api.ts (4)

1-1: Mark this module server-only to prevent client bundling.

Ensure this file cannot be imported into client components.

+import 'server-only';

23-42: Add timeout, no-store caching, and richer error details in fetch wrapper.

Prevents hanging requests, stale data, and surfaces server error bodies.

-  private async makeRequest<T>(
-    endpoint: string,
-    options: RequestInit = {}
-  ): Promise<T> {
-    const url = `${API_BASE_URL}${endpoint}`;
-    
-    const response = await fetch(url, {
-      headers: {
-        'Content-Type': 'application/json',
-        ...options.headers,
-      },
-      ...options,
-    });
-
-    if (!response.ok) {
-      throw new Error(`API request failed: ${response.status} ${response.statusText}`);
-    }
-
-    return response.json();
-  }
+  private async makeRequest<T>(
+    endpoint: string,
+    options: RequestInit = {},
+    timeoutMs: number = 10000
+  ): Promise<T> {
+    const url = `${API_BASE_URL}${endpoint}`;
+    const controller = new AbortController();
+    const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
+    try {
+      const headers = {
+        'Content-Type': 'application/json',
+        Accept: 'application/json',
+        ...(options.headers || {}),
+      } as Record<string, string>;
+
+      const response = await fetch(url, {
+        ...options,
+        headers,
+        cache: 'no-store',
+        signal: controller.signal,
+      });
+
+      if (!response.ok) {
+        const bodyText = await response.text().catch(() => '');
+        throw new Error(
+          `API request failed: ${response.status} ${response.statusText}${bodyText ? ` - ${bodyText}` : ''}`
+        );
+      }
+      return response.json() as Promise<T>;
+    } finally {
+      clearTimeout(timeoutId);
+    }
+  }

50-60: URL-encode all path segments to handle special characters safely.

Apply encodeURIComponent to namespace, graphName, stateId, and runId.

-      `/v0/namespace/${namespace}/nodes/`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/nodes/`,
@@
-      `/v0/namespace/${namespace}/graph/${graphName}`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/graph/${encodeURIComponent(graphName)}`,
@@
-      `/v0/namespace/${namespace}/graph/${graphName}/states/create`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/graph/${encodeURIComponent(graphName)}/states/create`,
@@
-      `/v0/namespace/${namespace}/states/enqueue`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/states/enqueue`,
@@
-      `/v0/namespace/${namespace}/states/${stateId}/executed`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/states/${encodeURIComponent(stateId)}/executed`,
@@
-      `/v0/namespace/${namespace}/state/${stateId}/secrets`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/state/${encodeURIComponent(stateId)}/secrets`,
@@
-      `/v0/namespace/${namespace}/nodes/`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/nodes/`,
@@
-      `/v0/namespace/${namespace}/graphs/`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/graphs/`,
@@
-      `/v0/namespace/${namespace}/states/run/${runId}/graph`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/states/run/${encodeURIComponent(runId)}/graph`,
@@
-      `/v0/namespace/${namespace}/runs/${page}/${size}`,
+      `/v0/namespace/${encodeURIComponent(namespace)}/runs/${page}/${size}`,

Also applies to: 81-95, 97-114, 116-131, 133-149, 151-165, 167-181, 183-196, 200-214, 217-232


216-233: Validate and clamp pagination inputs.

Prevents negative/NaN values and unbounded page sizes.

-  async getRuns(
-    namespace: string,
-    apiKey: string,
-    page: number = 1,
-    size: number = 20
-  ): Promise<RunsResponse> {
-    return this.makeRequest<RunsResponse>(
-      `/v0/namespace/${namespace}/runs/${page}/${size}`,
+  async getRuns(
+    namespace: string,
+    apiKey: string,
+    page: number = 1,
+    size: number = 20
+  ): Promise<RunsResponse> {
+    const safePage = Math.max(1, Math.floor(page || 1));
+    const safeSize = Math.max(1, Math.min(100, Math.floor(size || 20)));
+    return this.makeRequest<RunsResponse>(
+      `/v0/namespace/${encodeURIComponent(namespace)}/runs/${safePage}/${safeSize}`,
       {
         method: 'GET',
         headers: {
           'X-API-Key': apiKey,
         },
       }
     );
   }
♻️ Duplicate comments (12)
state-manager/app/controller/errored_state.py (1)

65-69: Return RETRY_CREATED when a retry is created/detected

You correctly set the parent state to RETRY_CREATED, but the API still returns ERRORED. Make the response reflect the outcome.

-        return ErroredResponseModel(status=StateStatusEnum.ERRORED, retry_created=retry_created)
+        status_to_return = StateStatusEnum.RETRY_CREATED if retry_created else StateStatusEnum.ERRORED
+        return ErroredResponseModel(status=status_to_return, retry_created=retry_created)

Also applies to: 73-73

docs/docs/exosphere/create-runtime.md (1)

17-18: Clarify auth wording; use “state manager” consistently.

Tighten phrasing and make the requirement explicit.

- > **🔐 Authentication**: When making API requests to the state manager, the `EXOSPHERE_API_KEY` value is compared to the `STATE_MANAGER_SECRET` value in the state manager container.
+> **🔐 Authentication**: API requests to the state manager are authorized only if `EXOSPHERE_API_KEY` equals `STATE_MANAGER_SECRET` configured in the state manager container.
dashboard/SECURITY.md (2)

21-25: Remove hardcoded API key from docs; use a placeholder and guidance.

Publishing a sample secret invites copy/paste into real deployments.

-```bash
-EXOSPHERE_STATE_MANAGER_URI=http://localhost:8000
-EXOSPHERE_API_KEY=exosphere@123
-```
+```bash
+EXOSPHERE_STATE_MANAGER_URI=http://localhost:8000
+# Set via a runtime secret; do NOT commit to VCS
+EXOSPHERE_API_KEY=<set-at-runtime>
+```

50-55: Do not imply a default secret; require a strong unique key.

Replace “Optional/default” language; clarify equality with manager’s secret.

-2. **Optional**: Override the default API key in `EXOSPHERE_API_KEY` (defaults to `exosphere@123`, same as `STATE_MANAGER_SECRET` in the state manager container)
-3. **Authentication**: The `EXOSPHERE_API_KEY` value is checked for equality with the `STATE_MANAGER_SECRET` value when making API requests to the state-manager
+2. Set a strong, unique `EXOSPHERE_API_KEY` via your secret manager (do not commit `.env` files).
+3. The dashboard uses `EXOSPHERE_API_KEY` when calling the state manager; it must exactly match the manager’s `STATE_MANAGER_SECRET`.
docs/docs/docker-compose-setup.md (3)

154-161: Fix heading semantics and table rendering; remove misleading “REQUIRED” label

Add a blank line before the table so it renders, de-emphasize the heading formatting, and avoid calling the key “REQUIRED” while also providing a default.

-#### 🔒 **Server-Side Variables (REQUIRED - NOT exposed to browser)**
+#### 🔒 Server-side variables (not exposed to browser)
+
 | Variable | Description | Default Value |
 |----------|-------------|---------------|
 | `EXOSPHERE_STATE_MANAGER_URI` | State manager API URI | `http://exosphere-state-manager:8000` |
-| `EXOSPHERE_API_KEY` | **REQUIRED**: Secure API key for state manager access | `exosphere@123` |
+| `EXOSPHERE_API_KEY` | Secure API key for state manager access (set a strong, unique value in production) | `exosphere@123` |

162-166: Add blank line before client-side variables table; align heading style

Ensures reliable Markdown rendering and consistent casing.

-#### 🌐 **Client-Side Variables (Optional - exposed to browser)**
+#### 🌐 Client-side variables (optional — exposed to browser)
+
 | Variable | Description | Default Value |
 |----------|-------------|---------------|
 | `NEXT_PUBLIC_DEFAULT_NAMESPACE` | Default namespace for workflows | `default` |

260-262: Production guidance: do not rely on the default API key

Make this explicit in the example to prevent insecure copy-paste.

-# Dashboard Configuration
-# Note: EXOSPHERE_API_KEY defaults to 'exosphere@123' if not specified
-EXOSPHERE_API_KEY=your-secure-api-key
+# Dashboard configuration
+# REQUIRED for production: set a strong, unique key. Do NOT rely on the default.
+EXOSPHERE_API_KEY=change-me-to-a-strong-unique-value
state-manager/tests/unit/test_routes.py (1)

55-57: Route tag check is brittle; use subset membership.
This was previously flagged; please allow multiple/future tags.

Apply:

-                assert route.tags in [["state"], ["graph"], ["nodes"], ["runs"]] # type: ignore
+                allowed = {"state", "graph", "nodes", "runs"}
+                route_tags = set(route.tags or [])  # type: ignore
+                assert route_tags and route_tags.issubset(allowed)  # type: ignore
state-manager/app/models/db/run.py (2)

3-3: Make timestamps timezone-aware (UTC).

Use tz-aware datetimes to avoid ordering/serialization bugs across services.

Apply:

-from datetime import datetime
+from datetime import datetime, timezone

11-11: created_at is naive; switch to UTC-aware default_factory.

Persist tz-aware values for correct sorting and API responses.

Apply:

-    created_at: datetime = Field(default_factory=datetime.now, description="Creation timestamp")
+    created_at: datetime = Field(
+        default_factory=lambda: datetime.now(timezone.utc),
+        description="Creation timestamp"
+    )
state-manager/tests/unit/controller/test_get_runs.py (2)

115-116: Patch async get_run_status with AsyncMock; current patches will fail at await.

get_run_info awaits get_run_status; MagicMock is not awaitable.

Apply:

-with patch('app.controller.get_runs.get_run_status') as mock_get_status:
+with patch('app.controller.get_runs.get_run_status', new_callable=AsyncMock) as mock_get_status:

Repeat for all occurrences listed.

Also applies to: 143-144, 163-164, 183-184


224-226: Patch async get_run_info with AsyncMock; asyncio.gather awaits it.

Using MagicMock will raise TypeError when awaited.

Apply:

- with patch('app.controller.get_runs.Run') as mock_run_class, \
-      patch('app.controller.get_runs.get_run_info') as mock_get_run_info, \
+ with patch('app.controller.get_runs.Run') as mock_run_class, \
+      patch('app.controller.get_runs.get_run_info', new_callable=AsyncMock) as mock_get_run_info, \
       patch('app.controller.get_runs.logger') as mock_logger:

For cases where you don’t use the variable (set to _), still add new_callable=AsyncMock.

Also applies to: 274-276, 391-393, 421-423, 449-451

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cb791bf and de24319.

📒 Files selected for processing (10)
  • dashboard/SECURITY.md (1 hunks)
  • dashboard/src/services/api.ts (3 hunks)
  • docs/docs/docker-compose-setup.md (4 hunks)
  • docs/docs/exosphere/create-runtime.md (2 hunks)
  • state-manager/app/controller/errored_state.py (1 hunks)
  • state-manager/app/models/db/run.py (1 hunks)
  • state-manager/tests/unit/controller/test_errored_state.py (1 hunks)
  • state-manager/tests/unit/controller/test_get_current_states.py (0 hunks)
  • state-manager/tests/unit/controller/test_get_runs.py (1 hunks)
  • state-manager/tests/unit/test_routes.py (7 hunks)
💤 Files with no reviewable changes (1)
  • state-manager/tests/unit/controller/test_get_current_states.py
🧰 Additional context used
🧬 Code graph analysis (5)
state-manager/tests/unit/controller/test_errored_state.py (1)
state-manager/app/models/state_status_enum.py (1)
  • StateStatusEnum (4-20)
state-manager/app/controller/errored_state.py (1)
state-manager/app/models/state_status_enum.py (1)
  • StateStatusEnum (4-20)
state-manager/tests/unit/controller/test_get_runs.py (3)
state-manager/app/controller/get_runs.py (3)
  • get_runs (34-50)
  • get_run_status (12-18)
  • get_run_info (20-31)
state-manager/app/models/db/run.py (1)
  • Run (7-25)
state-manager/app/models/run_models.py (1)
  • RunStatusEnum (9-12)
state-manager/tests/unit/test_routes.py (2)
state-manager/app/models/run_models.py (1)
  • RunStatusEnum (9-12)
state-manager/app/routes.py (2)
  • get_runs_route (304-313)
  • get_graph_structure_route (323-332)
dashboard/src/services/api.ts (1)
dashboard/src/types/state-manager.ts (2)
  • GraphStructureResponse (175-183)
  • RunsResponse (204-210)
🪛 LanguageTool
docs/docs/docker-compose-setup.md

[grammar] ~154-~154: Use correct spacing
Context: ...ta. ### Dashboard Environment Variables #### 🔒 **Server-Side Variables (REQUIRED - N...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[typographical] ~156-~156: To join two clauses or set off examples, consider using an em dash.
Context: ...ables #### 🔒 Server-Side Variables (REQUIRED - NOT exposed to browser) | Variable | Desc...

(QB_NEW_EN_DASH_RULE_EM)


[grammar] ~156-~156: There might be a mistake here.
Context: ...bles (REQUIRED - NOT exposed to browser)** | Variable | Description | Default Value...

(QB_NEW_EN)


[grammar] ~157-~157: There might be a mistake here.
Context: ...Variable | Description | Default Value | |----------|-------------|--------------...

(QB_NEW_EN)


[grammar] ~158-~158: There might be a mistake here.
Context: ...---------|-------------|---------------| | EXOSPHERE_STATE_MANAGER_URI | State ...

(QB_NEW_EN)


[grammar] ~159-~159: There might be a mistake here.
Context: ... http://exosphere-state-manager:8000 | | EXOSPHERE_API_KEY | REQUIRED: Se...

(QB_NEW_EN)


[grammar] ~160-~160: There might be a mistake here.
Context: ...state manager access | exosphere@123 | #### 🌐 **Client-Side Variables (Optional - e...

(QB_NEW_EN)


[typographical] ~162-~162: To join two clauses or set off examples, consider using an em dash.
Context: ...23` | #### 🌐 Client-Side Variables (Optional - exposed to browser) | Variable | Description ...

(QB_NEW_EN_DASH_RULE_EM)


[grammar] ~162-~162: There might be a mistake here.
Context: ...ariables (Optional - exposed to browser)** | Variable | Description | Default Value...

(QB_NEW_EN)


[grammar] ~163-~163: There might be a mistake here.
Context: ...Variable | Description | Default Value | |----------|-------------|--------------...

(QB_NEW_EN)


[grammar] ~164-~164: There might be a mistake here.
Context: ...---------|-------------|---------------| | NEXT_PUBLIC_DEFAULT_NAMESPACE | Defa...

(QB_NEW_EN)


[grammar] ~165-~165: There might be a mistake here.
Context: ...lt namespace for workflows | default | > 🔒 Security Note: The dashboard now us...

(QB_NEW_EN)


[grammar] ~167-~167: There might be a mistake here.
Context: ...Rendering (SSR)** for enhanced security: > - API keys are never exposed to the brow...

(QB_NEW_EN)


[grammar] ~168-~168: There might be a mistake here.
Context: ... keys are never exposed** to the browser > - All API calls go through secure server...

(QB_NEW_EN)


[grammar] ~169-~169: There might be a mistake here.
Context: ...s go through** secure server-side routes > - Production-ready security architecture...

(QB_NEW_EN)


[grammar] ~170-~170: There might be a mistake here.
Context: ...Production-ready security** architecture > - Environment isolation between sensitiv...

(QB_NEW_EN)


[grammar] ~171-~171: There might be a mistake here.
Context: ...tween sensitive and public configuration > > 💡 Default API Key: `EXOSPHERE_API_KEY...

(QB_NEW_EN)


[grammar] ~173-~173: There might be a mistake here.
Context: ...(same as state manager's default secret) > > 🔐 Authentication: When the dashboard ...

(QB_NEW_EN)


[grammar] ~175-~175: Use hyphens correctly
Context: ...ashboard sends API requests to the state-manager, the EXOSPHERE_API_KEY value i...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~175-~175: Use hyphens correctly
Context: ...STATE_MANAGER_SECRET` value in the state-manager container. ## 🔒 **Security Arc...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~175-~175: There might be a mistake here.
Context: ...T` value in the state-manager container. ## 🔒 Security Architecture ### **Serv...

(QB_NEW_EN)


[grammar] ~177-~177: There might be a mistake here.
Context: ...ontainer. ## 🔒 Security Architecture ### **Server-Side Rendering (SSR) Implementati...

(QB_NEW_EN)


[grammar] ~179-~179: Use correct spacing
Context: ...rver-Side Rendering (SSR) Implementation** The Exosphere Dashboard has been refacto...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~181-~181: Use correct spacing
Context: ...ext.js API routes for enhanced security: - API Key Protection: All sensitive cred...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~183-~183: Use hyphens correctly
Context: ...itive credentials are stored server-side - Secure Communication: Client never dir...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~184-~184: There might be a mistake here.
Context: ...n**: Client never directly communicates with state-manager - **Environment Isolation...

(QB_NEW_EN)


[grammar] ~184-~184: Use hyphens correctly
Context: ...t never directly communicates with state-manager - Environment Isolation: Sen...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~184-~184: Use hyphens correctly
Context: ...directly communicates with state-manager - Environment Isolation: Sensitive confi...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~185-~185: Use modal and auxiliary verbs correctly
Context: ... - Environment Isolation: Sensitive config separated from public code - **Producti...

(QB_NEW_EN_OTHER_ERROR_IDS_24)


[grammar] ~185-~185: There might be a mistake here.
Context: ...sitive config separated from public code - Production Ready: Enterprise-grade sec...

(QB_NEW_EN_OTHER)


[grammar] ~186-~186: There might be a mistake here.
Context: ...rade security for production deployments ### API Route Structure ``` /api/runs ...

(QB_NEW_EN_OTHER)


[grammar] ~188-~188: Use correct spacing
Context: ...n deployments ### API Route Structure /api/runs → Secure runs fetching with pagination /api/graph-structure → Protected graph visualization data /api/namespace-overview → Secure namespace summary /api/graph-template → Protected template management ### Security Benefits 1. **No API Key Exp...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~197-~197: Use correct spacing
Context: ... management ``` ### Security Benefits 1. No API Key Exposure: Credentials never...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~199-~199: There might be a mistake here.
Context: ...**: Credentials never visible in browser 2. Server-Side Validation: All requests v...

(QB_NEW_EN)


[grammar] ~200-~200: Use hyphens correctly
Context: ...requests validated before reaching state-manager 3. Environment Security: Sen...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~200-~200: There might be a mistake here.
Context: ... validated before reaching state-manager 3. Environment Security: Sensitive variab...

(QB_NEW_EN)


[grammar] ~201-~201: There might be a mistake here.
Context: ...ve variables isolated from client bundle 4. Audit Trail: All API calls logged serv...

(QB_NEW_EN)


[grammar] ~202-~202: Use correct spacing
Context: ... calls logged server-side for monitoring ### Docker Security Features - **Environm...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~204-~204: Use correct spacing
Context: ...nitoring ### Docker Security Features - Environment Variable Isolation: Server...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~206-~206: Use commas correctly
Context: ...ainers and available to server processes, but are not exposed to the browser/clie...

(QB_NEW_EN_OTHER_ERROR_IDS_33)


[grammar] ~206-~206: There might be a mistake here.
Context: ...not exposed to the browser/client bundle - Network Security: Services communicate...

(QB_NEW_EN_OTHER)


[grammar] ~207-~207: There might be a mistake here.
Context: ...ommunicate over isolated Docker networks - Health Checks: Built-in health monitor...

(QB_NEW_EN_OTHER)


[grammar] ~208-~208: There might be a mistake here.
Context: ...lt-in health monitoring for all services - Resource Limits: Configurable resource...

(QB_NEW_EN_OTHER)


[grammar] ~209-~209: There might be a mistake here.
Context: ... resource constraints for production use ### MongoDB Local Setup Variables (for docke...

(QB_NEW_EN_OTHER)


[grammar] ~232-~232: Use hyphens correctly
Context: ...*: When making API requests to the state-manager, the EXOSPHERE_API_KEY value i...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~232-~232: Use hyphens correctly
Context: ...STATE_MANAGER_SECRET` value in the state-manager container. *Example SDK setup...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~232-~232: There might be a mistake here.
Context: ...T` value in the state-manager container. Example SDK setup: ```bash # Set envir...

(QB_NEW_EN)


[grammar] ~431-~431: Use correct spacing
Context: ..._SECRET` value when making API requests. ## Next Steps Once your Exosphere instance...

(QB_NEW_EN_OTHER_ERROR_IDS_5)

docs/docs/exosphere/create-runtime.md

[grammar] ~17-~17: There might be a mistake here.
Context: ...T` value in the state manager container. 2. Set Environment Variables: Configure y...

(QB_NEW_EN)


[grammar] ~316-~316: There might be a mistake here.
Context: ...igger-graph.md)** - Execute and monitor workflows

(QB_NEW_EN_OTHER)

dashboard/SECURITY.md

[grammar] ~1-~1: Use correct spacing
Context: # Security Architecture ## Overview This dashboard has been refact...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~3-~3: Use correct spacing
Context: # Security Architecture ## Overview This dashboard has been refactored to us...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~5-~5: Use hyphens correctly
Context: ...ced security. All API calls to the state-manager are now handled server-side, kee...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~5-~5: Use correct spacing
Context: ...sitive information like API keys secure. ## Architecture Changes ### Before (Client...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~7-~7: Use correct spacing
Context: ...PI keys secure. ## Architecture Changes ### Before (Client-Side) - API key was visib...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~9-~9: There might be a mistake here.
Context: ...ecture Changes ### Before (Client-Side) - API key was visible in browser - Direct ...

(QB_NEW_EN)


[grammar] ~10-~10: There might be a mistake here.
Context: ...t-Side) - API key was visible in browser - Direct calls to state-manager from clien...

(QB_NEW_EN_OTHER)


[grammar] ~11-~11: Use hyphens correctly
Context: ...sible in browser - Direct calls to state-manager from client - Security risk in p...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~11-~11: There might be a mistake here.
Context: ...irect calls to state-manager from client - Security risk in production environments...

(QB_NEW_EN_OTHER)


[grammar] ~12-~12: There might be a mistake here.
Context: ...Security risk in production environments ### After (Server-Side) - API key stored sec...

(QB_NEW_EN_OTHER)


[grammar] ~14-~14: There might be a mistake here.
Context: ...on environments ### After (Server-Side) - API key stored securely in environment v...

(QB_NEW_EN)


[grammar] ~15-~15: There might be a mistake here.
Context: ...stored securely in environment variables - All API calls go through Next.js API rou...

(QB_NEW_EN)


[grammar] ~16-~16: There might be a mistake here.
Context: ... API calls go through Next.js API routes - Client never sees sensitive credentials ...

(QB_NEW_EN)


[grammar] ~17-~17: Use correct spacing
Context: ... Client never sees sensitive credentials ## Environment Variables ### Server-Side (...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~19-~19: Use correct spacing
Context: ...ve credentials ## Environment Variables ### Server-Side (NOT exposed to browser) ```...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~21-~21: Use correct spacing
Context: ...### Server-Side (NOT exposed to browser) bash EXOSPHERE_STATE_MANAGER_URI=http://localhost:8000 EXOSPHERE_API_KEY=exosphere@123 ### Client-Side (exposed to browser) ```bash...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~27-~27: Use correct spacing
Context: ...`` ### Client-Side (exposed to browser) bash NEXT_PUBLIC_DEFAULT_NAMESPACE=your-namespace ## API Routes The following server-side AP...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~32-~32: Use correct spacing
Context: ...ESPACE=your-namespace ``` ## API Routes The following server-side API routes han...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~34-~34: Use hyphens correctly
Context: ... handle all communication with the state-manager: - /api/runs - Fetch paginate...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~34-~34: Use correct spacing
Context: ...ll communication with the state-manager: - /api/runs - Fetch paginated runs - `/api/graph-st...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~36-~36: Use hyphens correctly
Context: ...r: - /api/runs - Fetch paginated runs - /api/graph-structure - Get graph visualization data - `/api/n...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~37-~37: Use hyphens correctly
Context: ...tructure- Get graph visualization data -/api/namespace-overview- Get namespace summary data -/api/gra...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~38-~38: Use hyphens correctly
Context: ...e-overview- Get namespace summary data -/api/graph-template` - Manage graph templates ## Security Be...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~39-~39: There might be a mistake here.
Context: ...graph-template` - Manage graph templates ## Security Benefits 1. **API Key Protecti...

(QB_NEW_EN_OTHER)


[grammar] ~41-~41: Use correct spacing
Context: ...ge graph templates ## Security Benefits 1. API Key Protection: API keys are never...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~43-~43: There might be a mistake here.
Context: ...API keys are never exposed to the client 2. Server-Side Validation: All requests a...

(QB_NEW_EN_OTHER)


[grammar] ~44-~44: Use hyphens correctly
Context: ...: All requests are validated server-side 3. Environment Isolation: Sensitive confi...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~45-~45: There might be a mistake here.
Context: ...sitive config separated from client code 4. Production Ready: Secure for deploymen...

(QB_NEW_EN_OTHER)


[grammar] ~46-~46: There might be a mistake here.
Context: ...or deployment in production environments ## Setup Instructions 1. Copy `env.example...

(QB_NEW_EN_OTHER)


[grammar] ~48-~48: Use correct spacing
Context: ...tion environments ## Setup Instructions 1. Copy env.example to .env.local 2. **...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~50-~50: There might be a mistake here.
Context: ... Instructions 1. Copy env.example to .env.local 2. Optional: Override the default API key...

(QB_NEW_EN)


[grammar] ~51-~51: There might be a mistake here.
Context: ..._SECRETin the state manager container) 3. **Authentication**: TheEXOSPHERE_API_KEY...

(QB_NEW_EN_OTHER)


[grammar] ~52-~52: Use hyphens correctly
Context: ...ue when making API requests to the state-manager 4. Configure your state-manager ...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~52-~52: Use hyphens correctly
Context: ...making API requests to the state-manager 4. Configure your state-manager URI in `EXO...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~53-~53: Use hyphens correctly
Context: ...he state-manager 4. Configure your state-manager URI in `EXOSPHERE_STATE_MANAGER_...

(QB_NEW_EN_OTHER_ERROR_IDS_29)


[grammar] ~53-~53: There might be a mistake here.
Context: ... 4. Configure your state-manager URI in EXOSPHERE_STATE_MANAGER_URI 5. Set your default namespace in `NEXT_PUBL...

(QB_NEW_EN)


[grammar] ~54-~54: Use correct spacing
Context: ...R_URI5. Set your default namespace inNEXT_PUBLIC_DEFAULT_NAMESPACE` ## Development vs Production - **Developme...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~56-~56: Use periods with abbreviations
Context: ...BLIC_DEFAULT_NAMESPACE` ## Development vs Production - Development: Uses loc...

(QB_NEW_EN_OTHER_ERROR_IDS_34)


[grammar] ~56-~56: Use correct spacing
Context: ...NAMESPACE` ## Development vs Production - Development: Uses localhost URLs and d...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~58-~58: There might be a mistake here.
Context: ... localhost URLs and development API keys - Production: Uses production URLs and s...

(QB_NEW_EN_OTHER)


[grammar] ~59-~59: There might be a mistake here.
Context: ...Uses production URLs and secure API keys - Environment: Automatically detects and...

(QB_NEW_EN_OTHER)


[grammar] ~60-~60: There might be a mistake here.
Context: ...tects and uses appropriate configuration ## Best Practices 1. **Never commit `.env....

(QB_NEW_EN_OTHER)


[grammar] ~62-~62: Use correct spacing
Context: ...opriate configuration ## Best Practices 1. Never commit .env.local to version c...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~64-~64: There might be a mistake here.
Context: ...commit .env.local** to version control 2. Use strong, unique API keys for produc...

(QB_NEW_EN_OTHER)


[grammar] ~65-~65: There might be a mistake here.
Context: ...strong, unique API keys** for production 3. Rotate API keys regularly 4. **Monitor...

(QB_NEW_EN_OTHER)


[grammar] ~66-~66: There might be a mistake here.
Context: ...duction 3. Rotate API keys regularly 4. Monitor API usage for security anomali...

(QB_NEW_EN_OTHER)


[grammar] ~67-~67: There might be a mistake here.
Context: ...nitor API usage** for security anomalies 5. Use HTTPS in production environments

(QB_NEW_EN_OTHER)


[grammar] ~68-~68: There might be a mistake here.
Context: ...nomalies 5. Use HTTPS in production environments

(QB_NEW_EN_OTHER)

🪛 markdownlint-cli2 (0.17.2)
docs/docs/docker-compose-setup.md

156-156: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


157-157: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


162-162: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


163-163: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


168-168: Lists should be surrounded by blank lines

(MD032, blanks-around-lists)


172-172: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


174-174: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


190-190: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/docs/exosphere/create-runtime.md

316-316: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


316-316: Files should end with a single newline character

(MD047, single-trailing-newline)

dashboard/SECURITY.md

9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


10-10: Lists should be surrounded by blank lines

(MD032, blanks-around-lists)


14-14: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


15-15: Lists should be surrounded by blank lines

(MD032, blanks-around-lists)


21-21: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


22-22: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


27-27: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


28-28: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


68-68: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


68-68: Files should end with a single newline character

(MD047, single-trailing-newline)

🔇 Additional comments (15)
state-manager/app/controller/errored_state.py (1)

61-64: Idempotency on DuplicateKeyError looks good

Catching DuplicateKeyError and setting retry_created=True makes the endpoint idempotent under races. Good change.

docs/docs/docker-compose-setup.md (2)

197-203: Security benefits section LGTM

Clear, accurate, and aligned with the architecture.


204-209: Corrected environment-variable handling LGTM

The revised wording correctly states server-side vars are set in containers but not exposed to the browser/client bundle.

state-manager/tests/unit/test_routes.py (9)

10-11: Switch to run-centric models import — LGTM.


48-48: Runs list route path assertion — LGTM.


293-295: New handler imports — LGTM.


309-311: Handler callability checks — LGTM.


815-816: Assertion placement — LGTM.


882-936: Pagination and edge cases — LGTM.


937-951: Service error propagation — LGTM.


952-968: Invalid API key path — LGTM.


969-999: Graph-structure route auth tests — LGTM.

state-manager/tests/unit/controller/test_get_runs.py (3)

218-267: Good coverage and realistic mocking of query chain.


326-345: Exception handling test is solid; verifies logging and propagation.


376-414: Large page size path covered; ensure AsyncMock is used (see prior comment).

@NiveditJain NiveditJain merged commit adbd1f3 into exospherehost:main Sep 2, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sort dashboard run_ids by datetime Default Environment variables not being picked by Dashboard application

1 participant