Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion casa-explorer-ui/src/components/mas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@

export {MASTable, MASDataTable, createMASColumns} from './mas-list';
export {MASInfoTab, MASAppsTab, MASScopesTab, MASTracesTab, MASDenyConditionsTab, MASAppsTable} from './mas-details';
export {MASGraphView} from './mas-graph';
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import {useCallback, useMemo, useState} from 'react';
import {lazy, Suspense, useCallback, useMemo, useState} from 'react';
import type React from 'react';
import {useNavigate} from 'react-router-dom';
import {PATHS} from '@/router/paths';
Expand Down Expand Up @@ -42,7 +42,7 @@ import {Button} from '@/components/ui/button';
import {Card} from '@/components/ui/card';
import {Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle} from '@/components/ui/dialog';
import {Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetClose} from '@/components/ui/sheet';
import {MASGraphView} from '@/components/mas/mas-graph';
const MASGraphView = lazy(() => import('@/components/mas/mas-graph/mas-graph-view').then(m => ({default: m.MASGraphView})));
import {toast} from 'sonner';
import type {MAS} from '@/types/mas.types';
import type {App, AppType, Tool} from '@/types/app.types';
Expand Down Expand Up @@ -348,13 +348,15 @@ export function MASAppsTable({mas, apps}: MASAppsTableProps) {
</div>
{view === 'graph' && (
<div className="mt-4">
<MASGraphView
mas={mas}
apps={apps}
onAppClick={openApp}
searchTerm={search}
selectedTypes={selectedTypes}
/>
<Suspense fallback={null}>
<MASGraphView
mas={mas}
apps={apps}
onAppClick={openApp}
searchTerm={search}
selectedTypes={selectedTypes}
/>
</Suspense>
</div>
)}
</div>
Expand Down
28 changes: 16 additions & 12 deletions casa-explorer-ui/src/router/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,31 @@
* limitations under the License.
*/

import {lazy, Suspense} from 'react';
import {createBrowserRouter} from 'react-router-dom';
import {AppLayout} from '@/components/app-layout';
import {DashboardPage} from '@/pages/dashboard-page';
import {MASPage} from '@/pages/mas/mas-page';
import {MASDetailPage} from '@/pages/mas/mas-detail-page';
import {AuthRequestsPage} from '@/pages/auth-requests/auth-requests-page';
import {AuthRequestDetailPage} from '@/pages/auth-requests/auth-request-detail-page';
import {NotFoundPage} from '@/pages/not-found-page';
import {PATHS} from './paths';

const DashboardPage = lazy(() => import('@/pages/dashboard-page').then(m => ({default: m.DashboardPage})));
const MASPage = lazy(() => import('@/pages/mas/mas-page').then(m => ({default: m.MASPage})));
const MASDetailPage = lazy(() => import('@/pages/mas/mas-detail-page').then(m => ({default: m.MASDetailPage})));
const AuthRequestsPage = lazy(() => import('@/pages/auth-requests/auth-requests-page').then(m => ({default: m.AuthRequestsPage})));
const AuthRequestDetailPage = lazy(() => import('@/pages/auth-requests/auth-request-detail-page').then(m => ({default: m.AuthRequestDetailPage})));
const NotFoundPage = lazy(() => import('@/pages/not-found-page').then(m => ({default: m.NotFoundPage})));

const S = ({children}: {children: React.ReactNode}) => <Suspense fallback={null}>{children}</Suspense>;

export const router = createBrowserRouter([
{
path: PATHS.dashboard,
element: <AppLayout />,
children: [
{index: true, element: <DashboardPage />},
{path: PATHS.mas.list, element: <MASPage />},
{path: PATHS.mas.detailPattern, element: <MASDetailPage />},
{path: PATHS.authRequests.list, element: <AuthRequestsPage />},
{path: PATHS.authRequests.detailPattern, element: <AuthRequestDetailPage />},
{path: '*', element: <NotFoundPage />}
{index: true, element: <S><DashboardPage /></S>},
{path: PATHS.mas.list, element: <S><MASPage /></S>},
{path: PATHS.mas.detailPattern, element: <S><MASDetailPage /></S>},
{path: PATHS.authRequests.list, element: <S><AuthRequestsPage /></S>},
{path: PATHS.authRequests.detailPattern, element: <S><AuthRequestDetailPage /></S>},
{path: '*', element: <S><NotFoundPage /></S>}
]
}
]);
21 changes: 21 additions & 0 deletions casa-explorer-ui/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ export default defineConfig({
'@': path.resolve(__dirname, './src')
}
},
build: {
chunkSizeWarningLimit: 1600,
rollupOptions: {
output: {
manualChunks(id) {
if (!id.includes('node_modules')) return;
if (id.includes('elkjs') || id.includes('@xyflow')) return 'vendor-flow';
if (id.includes('recharts') || id.includes('/d3-') || id.includes('/d3/')) return 'vendor-charts';
if (id.includes('@dnd-kit')) return 'vendor-dnd';
if (id.includes('@tanstack')) return 'vendor-query';
if (id.includes('@tabler') || id.includes('lucide-react')) return 'vendor-icons';
if (id.includes('react-hook-form') || id.includes('@hookform') || id.includes('/zod/')) return 'vendor-forms';
if (
id.includes('@radix-ui') || id.includes('radix-ui') ||
id.includes('/cmdk/') || id.includes('/vaul/')
) return 'vendor-radix';
if (id.includes('react-router') || id.includes('react-dom') || id.match(/\/react\//) || id.includes('/sonner/') || id.includes('next-themes')) return 'vendor-react';
}
}
}
},
server: {
port: 1234,
open: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ data:
location /api/ {
proxy_pass {{ include "casa-runtime.authServiceUrl" . }}/;
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Expand Down
3 changes: 2 additions & 1 deletion deployments/helm/casa-runtime/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ uiExplorer:
nginx:
# When true, nginx proxies /api/ → auth-service (port 8000).
# Build the UI image with VITE_API_BASE_URL=/api when this is enabled.
# When false, the UI image must be built with the full auth-service URL.
# When false (minikube), build with VITE_API_BASE_URL=http://api.<domain> and
# enable authService.ingress so the browser calls the auth-service directly.
apiProxyEnabled: true

# ─── PostgreSQL (auth-service backend) ───────────────────────────────────────
Expand Down
52 changes: 45 additions & 7 deletions scripts/dev/local-setup-standalone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ log "Step 4 — Build control plane images"
docker build -f deployments/docker/Dockerfile -t casa-auth-server:local .
docker build -f deployments/docker/Dockerfile.keycloak -t casa-auth-server-keycloak:local deployments/docker
docker build -f deployments/docker/Dockerfile.operator -t casa-operator:local .
docker build --no-cache -f deployments/docker/Dockerfile.ui -t casa-auth-server-ui:local .
docker build --no-cache -f deployments/docker/Dockerfile.ui \
--build-arg VITE_API_BASE_URL=http://api.casa.outshift.ai \
-t casa-auth-server-ui:local .
docker build -f deployments/docker/Dockerfile.extauth -t ext-auth-service:local .

log "Step 4 — Build demo images"
Expand Down Expand Up @@ -164,7 +166,11 @@ helm upgrade --install casa-dev \
--set uiExplorer.ingress.className=nginx \
--set uiExplorer.ingress.apiDomainName=casa.outshift.ai \
--set uiExplorer.ingress.domainPrefix=explorer \
--set-string 'uiExplorer.ingress.annotations.nginx\.ingress\.kubernetes\.io/ssl-redirect=false' \
--set uiExplorer.nginx.apiProxyEnabled=false \
--set authService.ingress.enabled=true \
--set authService.ingress.className=nginx \
--set authService.ingress.apiDomainName=casa.outshift.ai \
--set authService.ingress.domainPrefix=api \
--set keycloak.image.repository=casa-auth-server-keycloak \
--set keycloak.image.tag=local \
--set keycloak.image.pullPolicy=Never \
Expand Down Expand Up @@ -233,7 +239,6 @@ helm upgrade --install casa-demo \
--set 'chatUis[0].ingress.className=nginx' \
--set 'chatUis[0].ingress.apiDomainName=casa.outshift.ai' \
--set 'chatUis[0].ingress.domainPrefix=chat-safe' \
--set-string 'chatUis[0].ingress.annotations.nginx\.ingress\.kubernetes\.io/ssl-redirect=false' \
--set 'chatUis[1].name=compromised' \
--set 'chatUis[1].docker.registry=' \
--set 'chatUis[1].docker.image=demo-chat-ui' \
Expand All @@ -243,7 +248,6 @@ helm upgrade --install casa-demo \
--set 'chatUis[1].ingress.className=nginx' \
--set 'chatUis[1].ingress.apiDomainName=casa.outshift.ai' \
--set 'chatUis[1].ingress.domainPrefix=chat-compromised' \
--set-string 'chatUis[1].ingress.annotations.nginx\.ingress\.kubernetes\.io/ssl-redirect=false' \
--set "llmCredentials.apiBaseUrl=${CASA_LLM_API_BASE_URL}" \
--set "llmCredentials.apiKey=${CASA_LLM_API_KEY}" \
--set 'masSafe.name=CASA Demo Safe' \
Expand All @@ -257,6 +261,39 @@ helm upgrade --install casa-demo \
--set 'masCompromised.enabledToolChecks[2]=AI_POWERED_TOOL_MATCH' \
--set "masCompromised.llm_host=${CASA_LLM_HOST}"

log "Step 6b. — Patching ingress annotations (minikube-specific)"
kubectl annotate ingress \
casa-dev-ui-explorer \
-n "$NAMESPACE" \
"nginx.ingress.kubernetes.io/ssl-redirect=false" \
"nginx.ingress.kubernetes.io/proxy-buffer-size=256k" \
"nginx.ingress.kubernetes.io/proxy-buffers-number=8" \
"nginx.ingress.kubernetes.io/proxy-body-size=20m" \
"nginx.ingress.kubernetes.io/proxy-read-timeout=300" \
"nginx.ingress.kubernetes.io/proxy-send-timeout=300" \
--overwrite

kubectl annotate ingress \
casa-dev-auth-service \
-n "$NAMESPACE" \
"nginx.ingress.kubernetes.io/ssl-redirect=false" \
"nginx.ingress.kubernetes.io/proxy-buffering=off" \
"nginx.ingress.kubernetes.io/proxy-buffer-size=128k" \
"nginx.ingress.kubernetes.io/proxy-read-timeout=300" \
"nginx.ingress.kubernetes.io/proxy-send-timeout=300" \
--overwrite

kubectl annotate ingress \
casa-demo-chat-ui-safe \
casa-demo-chat-ui-compromised \
-n "$NAMESPACE" \
"nginx.ingress.kubernetes.io/ssl-redirect=false" \
"nginx.ingress.kubernetes.io/proxy-buffering=off" \
"nginx.ingress.kubernetes.io/proxy-buffer-size=128k" \
"nginx.ingress.kubernetes.io/proxy-read-timeout=300" \
"nginx.ingress.kubernetes.io/proxy-send-timeout=300" \
--overwrite

# ---------------------------------------------------------------------------
# 7. Verify
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -293,11 +330,11 @@ kubectl port-forward -n "$NAMESPACE" svc/casa-dev-postgres-auth 5432:5432 &
kubectl port-forward -n "$NAMESPACE" svc/casa-dev-keycloak 8080:8080 &
kubectl port-forward -n "$NAMESPACE" svc/jaeger 16686:16686 &

# nginx ingress controller — exposes all 3 UIs on port 80 (requires sudo on macOS)
# nginx ingress controller — exposes all UIs on port 80 (requires sudo on macOS)
sudo -n kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80 &

log "Step 8 — Updating /etc/hosts for ingress hostnames"
HOSTS_LINE="127.0.0.1 explorer.casa.outshift.ai chat-safe.casa.outshift.ai chat-compromised.casa.outshift.ai"
HOSTS_LINE="127.0.0.1 explorer.casa.outshift.ai api.casa.outshift.ai chat-safe.casa.outshift.ai chat-compromised.casa.outshift.ai"
if grep -q "casa.outshift.ai" /etc/hosts; then
sudo sed -i '' '/casa\.outshift\.ai/d' /etc/hosts
fi
Expand All @@ -311,7 +348,8 @@ echo " Keycloak → http://localhost:8080"
echo " Jaeger traces → http://localhost:16686"
echo ""
echo "UIs available via nginx ingress:"
echo " Explorer UI → http://explorer.casa.outshift.ai"
echo " Explorer UI → http://explorer.casa.outshift.ai"
echo " Auth API → http://api.casa.outshift.ai"
echo " Safe chat UI → http://chat-safe.casa.outshift.ai"
echo " Compromised UI → http://chat-compromised.casa.outshift.ai"
echo ""
Expand Down
8 changes: 7 additions & 1 deletion src/casa_auth_server/telemetry/tracer_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from uuid import UUID, uuid4

from pydantic import BaseModel, ConfigDict
from sqlalchemy import DateTime, Integer, String, case, literal, union_all
from sqlalchemy import DateTime, Index, Integer, String, case, literal, text, union_all
from sqlalchemy import cast as sa_cast
from sqlmodel import JSON, Column, Field, Session, SQLModel, asc, desc, func, select

Expand Down Expand Up @@ -49,6 +49,12 @@ class Trace(SQLModel, table=True): # type: ignore[call-arg]
event_type: str
event: dict[str, Any] = Field(sa_column=Column(JSON))

__table_args__ = (
Index("ix_trace_event_mas_id", text("(event->>'mas_id')")),
Index("ix_trace_created_at", "created_at"),
Index("ix_trace_event_type", "event_type"),
)


class TraceList(BaseModel):
"""Paginated list of events."""
Expand Down
Loading