Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 45
Fixing dashboard#335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Fixing dashboard #335
Changes from all commits
c9cf63a9ff2accc55271d652f840a3143e1f67f1d3544a591017b1e38cc8de389c8e9fdba60fa86efd58f0e3a8354fe722cb791bfbb0d8b0d66892c14693d4a506f20faf33a7d61438b02e7d309db988e755341f8e03aae9b31ba2de24319File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -4,6 +4,12 @@ A modern Next.js dashboard for visualizing and managing the Exosphere State Mana | ||
| ## ✨ Features | ||
| ### 🔒 **Secure Server-Side Architecture** | ||
| - **Server-Side Rendering (SSR)**: All API calls handled securely on the server | ||
| - **Protected API Keys**: Sensitive credentials never exposed to the browser | ||
| - **Production Ready**: Enterprise-grade security for production deployments | ||
| - **Environment Isolation**: Secure separation of sensitive and public configuration | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ### 📊 Overview Dashboard | ||
| - **Namespace Overview**: Comprehensive view of your state manager namespace | ||
| - **Real-time Statistics**: Live metrics and status indicators | ||
| @@ -38,6 +44,7 @@ A modern Next.js dashboard for visualizing and managing the Exosphere State Mana | ||
| - **Node.js 18+** | ||
| - **A running State Manager backend** (default: http://localhost:8000) | ||
| - **Valid API key and namespace** | ||
| - **Environment configuration file** (`.env.local`) | ||
| ### Quick Start | ||
| @@ -57,8 +64,9 @@ npm install | ||
| cp env.example .env.local | ||
| # Edit .env.local with your configuration | ||
| NEXT_PUBLIC_EXOSPHERE_STATE_MANAGER_URL=http://localhost:8000 | ||
| NEXT_PUBLIC_DEV_MODE=true | ||
| EXOSPHERE_STATE_MANAGER_URI=http://localhost:8000 | ||
| EXOSPHERE_API_KEY=your-secure-api-key-here | ||
| NEXT_PUBLIC_DEFAULT_NAMESPACE=your-namespace | ||
| ``` | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| 4. **Start the development server:** | ||
| @@ -70,16 +78,24 @@ npm run dev | ||
| ### Environment Configuration | ||
| The dashboard supports the following environment variables: | ||
| The dashboard uses a secure server-side architecture with the following environment variables: | ||
| #### 🔒 **Server-Side Variables (NOT exposed to browser)** | ||
| | Variable | Default | Description | | ||
| |----------|---------|-------------| | ||
| | `EXOSPHERE_STATE_MANAGER_URI` | `http://localhost:8000` | URI of the State Manager backend API | | ||
| | `EXOSPHERE_API_KEY` | `exosphere@123` | **REQUIRED**: Your secure API key for state manager access | | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| #### 🌐 **Client-Side Variables (exposed to browser)** | ||
| | Variable | Default | Description | | ||
| |----------|---------|-------------| | ||
| | `NEXT_PUBLIC_EXOSPHERE_STATE_MANAGER_URL` | `http://localhost:8000` | URL of the State Manager backend API | | ||
| | `NEXT_PUBLIC_DEV_MODE` | `false` | Enable development mode features | | ||
| | `NEXT_PUBLIC_DEFAULT_NAMESPACE` | - | Default namespace to use | | ||
| | `NEXT_PUBLIC_DEFAULT_API_KEY` | - | Default API key (use with caution) | | ||
| | `NEXT_PUBLIC_DEFAULT_RUNTIME_NAME` | - | Default runtime name | | ||
| | `NEXT_PUBLIC_DEFAULT_GRAPH_NAME` | - | Default graph name | | ||
| | `NEXT_PUBLIC_DEFAULT_NAMESPACE` | `testnamespace` | Default namespace to use on dashboard startup | | ||
| > **⚠️ Security Note**: Server-side variables are never exposed to the browser, keeping your API keys secure. | ||
| > | ||
| > **💡 Default API Key**: `EXOSPHERE_API_KEY` defaults to `exosphere@123` (same as `STATE_MANAGER_SECRET` in the state manager container) | ||
| > | ||
| > **🔐 Authentication**: When the dashboard sends API requests to the state-manager, the `EXOSPHERE_API_KEY` value is checked for equality with the `STATE_MANAGER_SECRET` value in the state-manager container. | ||
| ## 🐳 Docker Deployment | ||
| @@ -90,14 +106,49 @@ The dashboard supports the following environment variables: | ||
| docker build -t exosphere-dashboard . | ||
| ``` | ||
| 2. **Run the container:** | ||
| 2. **Run the container with secure environment variables:** | ||
| ```bash | ||
| docker run -d \ | ||
| -p 3000:3000 \ | ||
| -e NEXT_PUBLIC_EXOSPHERE_STATE_MANAGER_URL=http://your-state-manager-url:8000 \ | ||
| -e EXOSPHERE_STATE_MANAGER_URI=http://your-state-manager-url:8000 \ | ||
| -e EXOSPHERE_API_KEY=your-secure-api-key \ | ||
| -e NEXT_PUBLIC_DEFAULT_NAMESPACE=your-namespace \ | ||
| exosphere-dashboard | ||
| ``` | ||
| > **🔒 Security**: API keys are securely handled server-side and never exposed to the browser. | ||
| > | ||
| > **💡 Default API Key**: If not specified, `EXOSPHERE_API_KEY` defaults to `exosphere@123` (same as `STATE_MANAGER_SECRET` in the state manager container) | ||
| > | ||
| > **🔐 Authentication**: When the dashboard sends API requests to the state-manager, the `EXOSPHERE_API_KEY` value is checked for equality with the `STATE_MANAGER_SECRET` value in the state-manager container. | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ## 🔒 Security Architecture | ||
| ### **Server-Side Rendering (SSR) Implementation** | ||
| The dashboard has been refactored to use Next.js API routes for enhanced security: | ||
| - **API Key Protection**: All sensitive credentials are stored server-side | ||
| - **Secure Communication**: Client never directly communicates with state-manager | ||
| - **Environment Isolation**: Sensitive config separated from public code | ||
| - **Production Ready**: Enterprise-grade security for production 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 Exposure**: Credentials never visible in browser | ||
| 2. **Server-Side Validation**: All requests validated before reaching state-manager | ||
| 3. **Environment Security**: Sensitive variables isolated from client bundle | ||
| 4. **Audit Trail**: All API calls logged server-side for monitoring | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ## 📖 Usage Guide | ||
| ### 1. Overview Dashboard | ||
| @@ -161,6 +212,8 @@ The dashboard integrates with the State Manager API endpoints: | ||
| - `POST /v0/namespace/{namespace}/states/enqueue` - Enqueue states | ||
| - `POST /v0/namespace/{namespace}/states/{state_id}/executed` - Execute state | ||
| - `GET /v0/namespace/{namespace}/state/{state_id}/secrets` - Get secrets | ||
| - `GET /v0/namespace/{namespace}/runs/{page}/{size}` - Get runs | ||
| - `GET /v0/namespace/{namespace}/states/run/{run_id}/graph` - Get graph structure for a run | ||
| ## 🏗️ Architecture | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Security Architecture | ||
| ## Overview | ||
| This dashboard has been refactored to use **Server-Side Rendering (SSR)** for enhanced security. All API calls to the state-manager are now handled server-side, keeping sensitive information like API keys secure. | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ## Architecture Changes | ||
| ### Before (Client-Side) | ||
| - API key was visible in browser | ||
| - Direct calls to state-manager from client | ||
| - Security risk in production environments | ||
| ### After (Server-Side) | ||
| - API key stored securely in environment variables | ||
| - All API calls go through Next.js API routes | ||
| - Client never sees sensitive credentials | ||
| ## Environment Variables | ||
| ### Server-Side (NOT exposed to browser) | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ```bash | ||
| EXOSPHERE_STATE_MANAGER_URI=http://localhost:8000 | ||
| EXOSPHERE_API_KEY=exosphere@123 | ||
| ``` | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ### Client-Side (exposed to browser) | ||
| ```bash | ||
| NEXT_PUBLIC_DEFAULT_NAMESPACE=your-namespace | ||
| ``` | ||
| ## API Routes | ||
| The following server-side API routes handle all communication with the state-manager: | ||
| - `/api/runs` - Fetch paginated runs | ||
| - `/api/graph-structure` - Get graph visualization data | ||
| - `/api/namespace-overview` - Get namespace summary data | ||
| - `/api/graph-template` - Manage graph templates | ||
| ## Security Benefits | ||
| 1. **API Key Protection**: API keys are never exposed to the client | ||
| 2. **Server-Side Validation**: All requests are validated server-side | ||
| 3. **Environment Isolation**: Sensitive config separated from client code | ||
| 4. **Production Ready**: Secure for deployment in production environments | ||
| ## Setup Instructions | ||
| 1. Copy `env.example` to `.env.local` | ||
| 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 | ||
| 4. Configure your state-manager URI in `EXOSPHERE_STATE_MANAGER_URI` | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| 5. Set your default namespace in `NEXT_PUBLIC_DEFAULT_NAMESPACE` | ||
| ## Development vs Production | ||
| - **Development**: Uses localhost URLs and development API keys | ||
| - **Production**: Uses production URLs and secure API keys | ||
| - **Environment**: Automatically detects and uses appropriate configuration | ||
| ## Best Practices | ||
| 1. **Never commit `.env.local`** to version control | ||
| 2. **Use strong, unique API keys** for production | ||
| 3. **Rotate API keys** regularly | ||
| 4. **Monitor API usage** for security anomalies | ||
| 5. **Use HTTPS** in production environments | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,11 @@ | ||
| # State Manager Frontend Environment Configuration | ||
| # State Manager Environment Configuration | ||
| # API Configuration | ||
| NEXT_PUBLIC_EXOSPHERE_STATE_MANAGER_URL=http://localhost:8000 | ||
| # Server-side API Configuration (NOT exposed to client) | ||
| EXOSPHERE_STATE_MANAGER_URI=http://localhost:8000 | ||
| EXOSPHERE_API_KEY=exosphere@123 | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| # Development Configuration | ||
| NEXT_PUBLIC_DEV_MODE=true | ||
| # Client-side Configuration (exposed to browser) | ||
| NEXT_PUBLIC_DEFAULT_NAMESPACE=your-namespace | ||
| # Optional: Override default configuration | ||
| # NEXT_PUBLIC_DEFAULT_NAMESPACE=your-namespace | ||
| # NEXT_PUBLIC_DEFAULT_API_KEY=your-api-key | ||
| # NEXT_PUBLIC_DEFAULT_RUNTIME_NAME=your-runtime | ||
| # NEXT_PUBLIC_DEFAULT_GRAPH_NAME=your-graph | ||
| # Development Configuration | ||
| NODE_ENV=development | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import { NextRequest, NextResponse } from 'next/server'; | ||
| const API_BASE_URL = process.env.EXOSPHERE_STATE_MANAGER_URI || 'http://localhost:8000'; | ||
| const API_KEY = process.env.EXOSPHERE_API_KEY; | ||
| export async function GET(request: NextRequest) { | ||
| try { | ||
| const { searchParams } = new URL(request.url); | ||
| const namespace = searchParams.get('namespace'); | ||
| const runId = searchParams.get('runId'); | ||
| if (!namespace || !runId) { | ||
| return NextResponse.json({ error: 'Namespace and runId are required' }, { status: 400 }); | ||
| } | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| if (!API_KEY) { | ||
| return NextResponse.json({ error: 'API key not configured' }, { status: 500 }); | ||
| } | ||
| const response = await fetch(`${API_BASE_URL}/v0/namespace/${namespace}/states/run/${runId}/graph`, { | ||
| headers: { | ||
| 'X-API-Key': API_KEY, | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| if (!response.ok) { | ||
| throw new Error(`State manager API error: ${response.status} ${response.statusText}`); | ||
| } | ||
| const data = await response.json(); | ||
| return NextResponse.json(data); | ||
| } catch (error) { | ||
| console.error('Error fetching graph structure:', error); | ||
| return NextResponse.json( | ||
| { error: 'Failed to fetch graph structure' }, | ||
| { status: 500 } | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import { NextRequest, NextResponse } from 'next/server'; | ||
| const API_BASE_URL = process.env.EXOSPHERE_STATE_MANAGER_URI || 'http://localhost:8000'; | ||
| const API_KEY = process.env.EXOSPHERE_API_KEY; | ||
| export async function GET(request: NextRequest) { | ||
| try { | ||
| const { searchParams } = new URL(request.url); | ||
| const namespace = searchParams.get('namespace'); | ||
| const graphName = searchParams.get('graphName'); | ||
| if (!namespace || !graphName) { | ||
| return NextResponse.json({ error: 'Namespace and graphName are required' }, { status: 400 }); | ||
| } | ||
| if (!API_KEY) { | ||
| return NextResponse.json({ error: 'API key not configured' }, { status: 500 }); | ||
| } | ||
| const response = await fetch(`${API_BASE_URL}/v0/namespace/${namespace}/graph/${graphName}`, { | ||
| headers: { | ||
| 'X-API-Key': API_KEY, | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| if (!response.ok) { | ||
| throw new Error(`State manager API error: ${response.status} ${response.statusText}`); | ||
| } | ||
| const data = await response.json(); | ||
| return NextResponse.json(data); | ||
| } catch (error) { | ||
| console.error('Error fetching graph template:', error); | ||
| return NextResponse.json( | ||
| { error: 'Failed to fetch graph template' }, | ||
| { status: 500 } | ||
| ); | ||
| } | ||
| } | ||
NiveditJain marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| export async function PUT(request: NextRequest) { | ||
| try { | ||
| const { searchParams } = new URL(request.url); | ||
| const namespace = searchParams.get('namespace'); | ||
| const graphName = searchParams.get('graphName'); | ||
| if (!namespace || !graphName) { | ||
| return NextResponse.json({ error: 'Namespace and graphName are required' }, { status: 400 }); | ||
| } | ||
| if (!API_KEY) { | ||
| return NextResponse.json({ error: 'API key not configured' }, { status: 500 }); | ||
| } | ||
| const body = await request.json(); | ||
| const response = await fetch(`${API_BASE_URL}/v0/namespace/${namespace}/graph/${graphName}`, { | ||
| method: 'PUT', | ||
| headers: { | ||
| 'X-API-Key': API_KEY, | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| body: JSON.stringify(body), | ||
| }); | ||
| if (!response.ok) { | ||
| throw new Error(`State manager API error: ${response.status} ${response.statusText}`); | ||
| } | ||
| const data = await response.json(); | ||
| return NextResponse.json(data); | ||
| } catch (error) { | ||
| console.error('Error updating graph template:', error); | ||
| return NextResponse.json( | ||
| { error: 'Failed to update graph template' }, | ||
| { status: 500 } | ||
| ); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.