diff --git a/casa-explorer-ui/src/components/mas/index.ts b/casa-explorer-ui/src/components/mas/index.ts index 7103f82b..be56047d 100644 --- a/casa-explorer-ui/src/components/mas/index.ts +++ b/casa-explorer-ui/src/components/mas/index.ts @@ -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'; diff --git a/casa-explorer-ui/src/components/mas/mas-details/mas-apps-table.tsx b/casa-explorer-ui/src/components/mas/mas-details/mas-apps-table.tsx index 577a8207..5668ca82 100644 --- a/casa-explorer-ui/src/components/mas/mas-details/mas-apps-table.tsx +++ b/casa-explorer-ui/src/components/mas/mas-details/mas-apps-table.tsx @@ -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'; @@ -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'; @@ -348,13 +348,15 @@ export function MASAppsTable({mas, apps}: MASAppsTableProps) { {view === 'graph' && (
- + + +
)} diff --git a/casa-explorer-ui/src/router/router.tsx b/casa-explorer-ui/src/router/router.tsx index 9d908228..17461bad 100644 --- a/casa-explorer-ui/src/router/router.tsx +++ b/casa-explorer-ui/src/router/router.tsx @@ -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}) => {children}; + export const router = createBrowserRouter([ { path: PATHS.dashboard, element: , children: [ - {index: true, element: }, - {path: PATHS.mas.list, element: }, - {path: PATHS.mas.detailPattern, element: }, - {path: PATHS.authRequests.list, element: }, - {path: PATHS.authRequests.detailPattern, element: }, - {path: '*', element: } + {index: true, element: }, + {path: PATHS.mas.list, element: }, + {path: PATHS.mas.detailPattern, element: }, + {path: PATHS.authRequests.list, element: }, + {path: PATHS.authRequests.detailPattern, element: }, + {path: '*', element: } ] } ]); diff --git a/casa-explorer-ui/vite.config.ts b/casa-explorer-ui/vite.config.ts index 57a63a53..ac5c7fc9 100644 --- a/casa-explorer-ui/vite.config.ts +++ b/casa-explorer-ui/vite.config.ts @@ -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 diff --git a/demo_new/helm/templates/banking-data-agent/deployment.yaml b/demo_new/helm/templates/banking-data-agent/deployment.yaml index 17d08a48..43d4bdbc 100644 --- a/demo_new/helm/templates/banking-data-agent/deployment.yaml +++ b/demo_new/helm/templates/banking-data-agent/deployment.yaml @@ -12,43 +12,45 @@ # See the License for the specific language governing permissions and # limitations under the License. +{{- range list .Values.bankingDataAgentA .Values.bankingDataAgentB }} +--- apiVersion: apps/v1 kind: Deployment metadata: - name: {{ .Values.bankingDataAgent.serviceName }} - namespace: {{ .Release.Namespace }} + name: {{ .serviceName }} + namespace: {{ $.Release.Namespace }} labels: - app: {{ .Values.bankingDataAgent.serviceName }} + app: {{ .serviceName }} version: v1 spec: - replicas: {{ .Values.bankingDataAgent.replicas }} + replicas: {{ .replicas }} selector: matchLabels: - app: {{ .Values.bankingDataAgent.serviceName }} + app: {{ .serviceName }} template: metadata: labels: - app: {{ .Values.bankingDataAgent.serviceName }} + app: {{ .serviceName }} version: v1 spec: - {{- if .Values.bankingDataAgent.docker.registry }} + {{- if .docker.registry }} imagePullSecrets: - name: regcred {{- end }} containers: - - name: {{ .Values.bankingDataAgent.serviceName }} - image: {{ if .Values.bankingDataAgent.docker.registry }}{{ .Values.bankingDataAgent.docker.registry }}/{{ end }}{{ .Values.bankingDataAgent.docker.image }}:{{ .Values.bankingDataAgent.tagversion }} - imagePullPolicy: {{ if .Values.bankingDataAgent.docker.registry }}Always{{ else }}Never{{ end }} + - name: {{ .serviceName }} + image: {{ if .docker.registry }}{{ .docker.registry }}/{{ end }}{{ .docker.image }}:{{ .tagversion }} + imagePullPolicy: {{ if .docker.registry }}Always{{ else }}Never{{ end }} securityContext: runAsNonRoot: true runAsUser: 999 allowPrivilegeEscalation: false ports: - - containerPort: {{ .Values.bankingDataAgent.servicePort }} + - containerPort: {{ .servicePort }} name: http env: - name: MCP_SERVER_URL - value: {{ .Values.bankingDataAgent.mcpServerUrl | quote }} + value: {{ .mcpServerUrl | quote }} - name: OPENAI_API_BASE valueFrom: secretKeyRef: @@ -66,3 +68,4 @@ spec: limits: memory: "512Mi" cpu: "500m" +{{- end }} diff --git a/demo_new/helm/templates/banking-data-agent/service.yaml b/demo_new/helm/templates/banking-data-agent/service.yaml index 5f6b329b..0d747f71 100644 --- a/demo_new/helm/templates/banking-data-agent/service.yaml +++ b/demo_new/helm/templates/banking-data-agent/service.yaml @@ -12,17 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. +{{- range list .Values.bankingDataAgentA .Values.bankingDataAgentB }} +--- apiVersion: v1 kind: Service metadata: - name: {{ .Values.bankingDataAgent.serviceName }} - namespace: {{ .Release.Namespace }} + name: {{ .serviceName }} + namespace: {{ $.Release.Namespace }} labels: - app: {{ .Values.bankingDataAgent.serviceName }} + app: {{ .serviceName }} spec: selector: - app: {{ .Values.bankingDataAgent.serviceName }} + app: {{ .serviceName }} ports: - name: http - port: {{ .Values.bankingDataAgent.servicePort }} + port: {{ .servicePort }} targetPort: http +{{- end }} diff --git a/demo_new/helm/templates/mas.yaml b/demo_new/helm/templates/mas.yaml index 8250a703..c4a7ce67 100644 --- a/demo_new/helm/templates/mas.yaml +++ b/demo_new/helm/templates/mas.yaml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Safe MAS: banking-assistant-safe, banking-data-agent, banking-payments-agent, banking-beneficiary-agent, banking-mcp. +# Safe MAS: banking-assistant-safe, banking-data-agent-a, banking-payments-agent-a, banking-beneficiary-agent-safe, banking-mcp-a. apiVersion: casa.io/v1alpha1 kind: MultiAgentSystem metadata: @@ -23,7 +23,7 @@ spec: enabledToolChecks: {{ toYaml .Values.masSafe.enabledToolChecks | nindent 4 }} llm_host: {{ .Values.masSafe.llm_host }} apps: - - name: {{ .Values.bankingAssistantSafe.serviceName }} + - name: {{ .Values.bankingAssistantSafe.appName }} type: agent baseUrl: host: {{ .Values.bankingAssistantSafe.serviceName }}:{{ .Values.bankingAssistantSafe.servicePort }} @@ -31,23 +31,23 @@ spec: kubernetesWorkloadName: {{ .Values.bankingAssistantSafe.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" - - name: {{ .Values.bankingDataAgent.serviceName }} + - name: {{ .Values.bankingDataAgentA.appName }} type: agent baseUrl: - host: {{ .Values.bankingDataAgent.serviceName }}:{{ .Values.bankingDataAgent.servicePort }} + host: {{ .Values.bankingDataAgentA.serviceName }}:{{ .Values.bankingDataAgentA.servicePort }} scheme: http - kubernetesWorkloadName: {{ .Values.bankingDataAgent.serviceName }} + kubernetesWorkloadName: {{ .Values.bankingDataAgentA.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" - - name: {{ .Values.bankingPaymentsAgent.serviceName }} + - name: {{ .Values.bankingPaymentsAgentA.appName }} type: agent baseUrl: - host: {{ .Values.bankingPaymentsAgent.serviceName }}:{{ .Values.bankingPaymentsAgent.servicePort }} + host: {{ .Values.bankingPaymentsAgentA.serviceName }}:{{ .Values.bankingPaymentsAgentA.servicePort }} scheme: http - kubernetesWorkloadName: {{ .Values.bankingPaymentsAgent.serviceName }} + kubernetesWorkloadName: {{ .Values.bankingPaymentsAgentA.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" - - name: {{ .Values.bankingBeneficiaryAgent.serviceName }} + - name: {{ .Values.bankingBeneficiaryAgent.appName }} type: agent baseUrl: host: {{ .Values.bankingBeneficiaryAgent.serviceName }}:{{ .Values.bankingBeneficiaryAgent.servicePort }} @@ -55,17 +55,17 @@ spec: kubernetesWorkloadName: {{ .Values.bankingBeneficiaryAgent.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" - - name: {{ .Values.mcp.serviceName }} + - name: {{ .Values.mcpA.appName }} type: mcp_server baseUrl: - host: {{ .Values.mcp.serviceName }}:{{ .Values.mcp.servicePort }} + host: {{ .Values.mcpA.serviceName }}:{{ .Values.mcpA.servicePort }} scheme: http - kubernetesWorkloadName: {{ .Values.mcp.serviceName }} + kubernetesWorkloadName: {{ .Values.mcpA.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" --- -# Compromised MAS: banking-assistant-compromised, banking-beneficiary-agent-compromised, banking-data-agent, banking-payments-agent, banking-mcp. +# Compromised MAS: banking-assistant-compromised, banking-beneficiary-agent-compromised, banking-data-agent-b, banking-payments-agent-b, banking-mcp-b. apiVersion: casa.io/v1alpha1 kind: MultiAgentSystem metadata: @@ -84,23 +84,23 @@ spec: kubernetesWorkloadName: {{ .Values.bankingAssistantCompromised.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" - - name: {{ .Values.bankingDataAgent.serviceName }} + - name: {{ .Values.bankingDataAgentB.appName }} type: agent baseUrl: - host: {{ .Values.bankingDataAgent.serviceName }}:{{ .Values.bankingDataAgent.servicePort }} + host: {{ .Values.bankingDataAgentB.serviceName }}:{{ .Values.bankingDataAgentB.servicePort }} scheme: http - kubernetesWorkloadName: {{ .Values.bankingDataAgent.serviceName }} + kubernetesWorkloadName: {{ .Values.bankingDataAgentB.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" - - name: {{ .Values.bankingPaymentsAgent.serviceName }} + - name: {{ .Values.bankingPaymentsAgentB.appName }} type: agent baseUrl: - host: {{ .Values.bankingPaymentsAgent.serviceName }}:{{ .Values.bankingPaymentsAgent.servicePort }} + host: {{ .Values.bankingPaymentsAgentB.serviceName }}:{{ .Values.bankingPaymentsAgentB.servicePort }} scheme: http - kubernetesWorkloadName: {{ .Values.bankingPaymentsAgent.serviceName }} + kubernetesWorkloadName: {{ .Values.bankingPaymentsAgentB.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" - - name: {{ .Values.bankingBeneficiaryAgentCompromised.serviceName }} + - name: {{ .Values.bankingBeneficiaryAgentCompromised.appName }} type: agent baseUrl: host: {{ .Values.bankingBeneficiaryAgentCompromised.serviceName }}:{{ .Values.bankingBeneficiaryAgentCompromised.servicePort }} @@ -108,11 +108,11 @@ spec: kubernetesWorkloadName: {{ .Values.bankingBeneficiaryAgentCompromised.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" - - name: {{ .Values.mcp.serviceName }} + - name: {{ .Values.mcpB.appName }} type: mcp_server baseUrl: - host: {{ .Values.mcp.serviceName }}:{{ .Values.mcp.servicePort }} + host: {{ .Values.mcpB.serviceName }}:{{ .Values.mcpB.servicePort }} scheme: http - kubernetesWorkloadName: {{ .Values.mcp.serviceName }} + kubernetesWorkloadName: {{ .Values.mcpB.serviceName }} httpRequestSchema: promptFieldJsonPath: "{.conversation}" diff --git a/demo_new/helm/templates/mcp/deployment.yaml b/demo_new/helm/templates/mcp/deployment.yaml index 6621d930..cd6f211f 100644 --- a/demo_new/helm/templates/mcp/deployment.yaml +++ b/demo_new/helm/templates/mcp/deployment.yaml @@ -12,39 +12,41 @@ # See the License for the specific language governing permissions and # limitations under the License. +{{- range list .Values.mcpA .Values.mcpB }} +--- apiVersion: apps/v1 kind: Deployment metadata: - name: {{ .Values.mcp.serviceName }} - namespace: {{ .Release.Namespace }} + name: {{ .serviceName }} + namespace: {{ $.Release.Namespace }} labels: - app: {{ .Values.mcp.serviceName }} + app: {{ .serviceName }} version: v1 spec: - replicas: {{ .Values.mcp.replicas }} + replicas: {{ .replicas }} selector: matchLabels: - app: {{ .Values.mcp.serviceName }} + app: {{ .serviceName }} template: metadata: labels: - app: {{ .Values.mcp.serviceName }} + app: {{ .serviceName }} version: v1 spec: - {{- if .Values.mcp.docker.registry }} + {{- if .docker.registry }} imagePullSecrets: - name: regcred {{- end }} containers: - - name: {{ .Values.mcp.serviceName }} - image: {{ if .Values.mcp.docker.registry }}{{ .Values.mcp.docker.registry }}/{{ end }}{{ .Values.mcp.docker.image }}:{{ .Values.mcp.tagversion }} - imagePullPolicy: {{ if .Values.mcp.docker.registry }}Always{{ else }}Never{{ end }} + - name: {{ .serviceName }} + image: {{ if .docker.registry }}{{ .docker.registry }}/{{ end }}{{ .docker.image }}:{{ .tagversion }} + imagePullPolicy: {{ if .docker.registry }}Always{{ else }}Never{{ end }} securityContext: runAsNonRoot: true runAsUser: 999 allowPrivilegeEscalation: false ports: - - containerPort: {{ .Values.mcp.servicePort }} + - containerPort: {{ .servicePort }} name: http resources: requests: @@ -53,3 +55,4 @@ spec: limits: memory: "256Mi" cpu: "250m" +{{- end }} diff --git a/demo_new/helm/templates/mcp/service.yaml b/demo_new/helm/templates/mcp/service.yaml index 5a00cd5f..fd78dbb0 100644 --- a/demo_new/helm/templates/mcp/service.yaml +++ b/demo_new/helm/templates/mcp/service.yaml @@ -12,17 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. +{{- range list .Values.mcpA .Values.mcpB }} +--- apiVersion: v1 kind: Service metadata: - name: {{ .Values.mcp.serviceName }} - namespace: {{ .Release.Namespace }} + name: {{ .serviceName }} + namespace: {{ $.Release.Namespace }} labels: - app: {{ .Values.mcp.serviceName }} + app: {{ .serviceName }} spec: selector: - app: {{ .Values.mcp.serviceName }} + app: {{ .serviceName }} ports: - name: http - port: {{ .Values.mcp.servicePort }} + port: {{ .servicePort }} targetPort: http +{{- end }} diff --git a/demo_new/helm/templates/payments-agent/deployment.yaml b/demo_new/helm/templates/payments-agent/deployment.yaml index 3bf5de80..e4b030a1 100644 --- a/demo_new/helm/templates/payments-agent/deployment.yaml +++ b/demo_new/helm/templates/payments-agent/deployment.yaml @@ -12,43 +12,45 @@ # See the License for the specific language governing permissions and # limitations under the License. +{{- range list .Values.bankingPaymentsAgentA .Values.bankingPaymentsAgentB }} +--- apiVersion: apps/v1 kind: Deployment metadata: - name: {{ .Values.bankingPaymentsAgent.serviceName }} - namespace: {{ .Release.Namespace }} + name: {{ .serviceName }} + namespace: {{ $.Release.Namespace }} labels: - app: {{ .Values.bankingPaymentsAgent.serviceName }} + app: {{ .serviceName }} version: v1 spec: - replicas: {{ .Values.bankingPaymentsAgent.replicas }} + replicas: {{ .replicas }} selector: matchLabels: - app: {{ .Values.bankingPaymentsAgent.serviceName }} + app: {{ .serviceName }} template: metadata: labels: - app: {{ .Values.bankingPaymentsAgent.serviceName }} + app: {{ .serviceName }} version: v1 spec: - {{- if .Values.bankingPaymentsAgent.docker.registry }} + {{- if .docker.registry }} imagePullSecrets: - name: regcred {{- end }} containers: - - name: {{ .Values.bankingPaymentsAgent.serviceName }} - image: {{ if .Values.bankingPaymentsAgent.docker.registry }}{{ .Values.bankingPaymentsAgent.docker.registry }}/{{ end }}{{ .Values.bankingPaymentsAgent.docker.image }}:{{ .Values.bankingPaymentsAgent.tagversion }} - imagePullPolicy: {{ if .Values.bankingPaymentsAgent.docker.registry }}Always{{ else }}Never{{ end }} + - name: {{ .serviceName }} + image: {{ if .docker.registry }}{{ .docker.registry }}/{{ end }}{{ .docker.image }}:{{ .tagversion }} + imagePullPolicy: {{ if .docker.registry }}Always{{ else }}Never{{ end }} securityContext: runAsNonRoot: true runAsUser: 999 allowPrivilegeEscalation: false ports: - - containerPort: {{ .Values.bankingPaymentsAgent.servicePort }} + - containerPort: {{ .servicePort }} name: http env: - name: MCP_SERVER_URL - value: {{ .Values.bankingPaymentsAgent.mcpServerUrl | quote }} + value: {{ .mcpServerUrl | quote }} - name: OPENAI_API_BASE valueFrom: secretKeyRef: @@ -66,3 +68,4 @@ spec: limits: memory: "512Mi" cpu: "500m" +{{- end }} diff --git a/demo_new/helm/templates/payments-agent/service.yaml b/demo_new/helm/templates/payments-agent/service.yaml index d97dd6fa..29a330b7 100644 --- a/demo_new/helm/templates/payments-agent/service.yaml +++ b/demo_new/helm/templates/payments-agent/service.yaml @@ -12,17 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. +{{- range list .Values.bankingPaymentsAgentA .Values.bankingPaymentsAgentB }} +--- apiVersion: v1 kind: Service metadata: - name: {{ .Values.bankingPaymentsAgent.serviceName }} - namespace: {{ .Release.Namespace }} + name: {{ .serviceName }} + namespace: {{ $.Release.Namespace }} labels: - app: {{ .Values.bankingPaymentsAgent.serviceName }} + app: {{ .serviceName }} spec: selector: - app: {{ .Values.bankingPaymentsAgent.serviceName }} + app: {{ .serviceName }} ports: - name: http - port: {{ .Values.bankingPaymentsAgent.servicePort }} + port: {{ .servicePort }} targetPort: http +{{- end }} diff --git a/demo_new/helm/values.yaml b/demo_new/helm/values.yaml index 1bbd4ba8..faed7a85 100644 --- a/demo_new/helm/values.yaml +++ b/demo_new/helm/values.yaml @@ -15,131 +15,172 @@ namespace: casa-dev masSafe: - name: "CASA Banking Demo Safe" - enabledToolChecks: - - DETERMINISTIC_TOOL_SELECTED - - AI_POWERED_TOOL_MATCH - llm_host: "" + name: "CASA Banking Demo Safe" + enabledToolChecks: + - DETERMINISTIC_TOOL_SELECTED + - AI_POWERED_TOOL_MATCH + llm_host: "" masCompromised: - name: "CASA Banking Demo Compromised" - enabledToolChecks: - - DETERMINISTIC_TOOL_SELECTED - - AI_POWERED_TOOL_MATCH - llm_host: "" + name: "CASA Banking Demo Compromised" + enabledToolChecks: + - DETERMINISTIC_TOOL_SELECTED + - AI_POWERED_TOOL_MATCH + llm_host: "" bankingAssistantSafe: - replicas: 1 - serviceName: banking-assistant-safe - servicePort: 8082 - compromisedMode: "false" - bankingDataAgentUrl: "http://banking-data-agent:8083" - paymentsAgentUrl: "http://banking-payments-agent:8084" - beneficiaryAgentUrl: "http://banking-beneficiary-agent:8085" - docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo-new/banking-assistant - suffix: '' - tagversion: latest + replicas: 1 + serviceName: banking-assistant-safe + appName: banking-assistant + servicePort: 8082 + compromisedMode: "false" + bankingDataAgentUrl: "http://banking-data-agent-a:8083" + paymentsAgentUrl: "http://banking-payments-agent-a:8084" + beneficiaryAgentUrl: "http://banking-beneficiary-agent-safe:8085" + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo-new/banking-assistant + suffix: "" + tagversion: latest bankingAssistantCompromised: - replicas: 1 - serviceName: banking-assistant-compromised - servicePort: 8082 - compromisedMode: "true" - bankingDataAgentUrl: "http://banking-data-agent:8083" - paymentsAgentUrl: "http://banking-payments-agent:8084" - beneficiaryAgentUrl: "http://banking-beneficiary-agent-compromised:8085" - docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo-new/banking-assistant - suffix: '' - tagversion: latest + replicas: 1 + serviceName: banking-assistant-compromised + servicePort: 8082 + compromisedMode: "true" + bankingDataAgentUrl: "http://banking-data-agent-b:8083" + paymentsAgentUrl: "http://banking-payments-agent-b:8084" + beneficiaryAgentUrl: "http://banking-beneficiary-agent-compromised:8085" + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo-new/banking-assistant + suffix: "" + tagversion: latest + +bankingDataAgentA: + replicas: 1 + serviceName: banking-data-agent-a + appName: data-agent + servicePort: 8083 + mcpServerUrl: "http://banking-mcp-a:3000/mcp" + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo-new/banking-data-agent + suffix: "" + tagversion: latest -bankingDataAgent: - replicas: 1 - serviceName: banking-data-agent - servicePort: 8083 - mcpServerUrl: "http://banking-mcp:3000/mcp" - docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo-new/banking-data-agent - suffix: '' - tagversion: latest +bankingDataAgentB: + replicas: 1 + serviceName: banking-data-agent-b + appName: data-agent + servicePort: 8083 + mcpServerUrl: "http://banking-mcp-b:3000/mcp" + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo-new/banking-data-agent + suffix: "" + tagversion: latest -bankingPaymentsAgent: - replicas: 1 - serviceName: banking-payments-agent - servicePort: 8084 - mcpServerUrl: "http://banking-mcp:3000/mcp" - docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo-new/payments-agent - suffix: '' - tagversion: latest +bankingPaymentsAgentA: + replicas: 1 + serviceName: banking-payments-agent-a + appName: payments-agent + servicePort: 8084 + mcpServerUrl: "http://banking-mcp-a:3000/mcp" + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo-new/payments-agent + suffix: "" + tagversion: latest + +bankingPaymentsAgentB: + replicas: 1 + serviceName: banking-payments-agent-b + appName: payments-agent + servicePort: 8084 + mcpServerUrl: "http://banking-mcp-b:3000/mcp" + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo-new/payments-agent + suffix: "" + tagversion: latest bankingBeneficiaryAgent: - replicas: 1 - serviceName: banking-beneficiary-agent - servicePort: 8085 - compromisedMode: "false" - mcpServerUrl: "http://banking-mcp:3000/mcp" - docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo-new/banking-beneficiary-agent - suffix: '' - tagversion: latest + replicas: 1 + serviceName: banking-beneficiary-agent-safe + appName: beneficiary-agent + servicePort: 8085 + compromisedMode: "false" + mcpServerUrl: "http://banking-mcp-a:3000/mcp" + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo-new/banking-beneficiary-agent + suffix: "" + tagversion: latest bankingBeneficiaryAgentCompromised: - replicas: 1 - serviceName: banking-beneficiary-agent-compromised - servicePort: 8085 - compromisedMode: "true" - mcpServerUrl: "http://banking-mcp:3000/mcp" - docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo-new/banking-beneficiary-agent - suffix: '' - tagversion: latest - -mcp: - replicas: 1 - serviceName: banking-mcp - servicePort: 3000 - docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo/mcp - suffix: '' - tagversion: latest + replicas: 1 + serviceName: banking-beneficiary-agent-compromised + appName: beneficiary-agent-compromised + servicePort: 8085 + compromisedMode: "true" + mcpServerUrl: "http://banking-mcp-b:3000/mcp" + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo-new/banking-beneficiary-agent + suffix: "" + tagversion: latest -chatUis: - - name: safe +mcpA: + replicas: 1 + serviceName: banking-mcp-a + appName: banking-mcp + servicePort: 3000 docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo/chat-ui + registry: ghcr.io/outshift-open + image: outshift-casa/demo/mcp + suffix: "" tagversion: latest - agentUrl: /safe-agent - ingress: - enabled: false - className: "nginx" - apiDomainName: "" - domainPrefix: "chat-safe" - annotations: - cert-manager.io/cluster-issuer: letsencrypt - - name: compromised + +mcpB: + replicas: 1 + serviceName: banking-mcp-b + appName: banking-mcp + servicePort: 3000 docker: - registry: ghcr.io/outshift-open - image: outshift-casa/demo/chat-ui + registry: ghcr.io/outshift-open + image: outshift-casa/demo/mcp + suffix: "" tagversion: latest - agentUrl: /compromised-agent - ingress: - enabled: false - className: "nginx" - apiDomainName: "" - domainPrefix: "chat-compromised" - annotations: - cert-manager.io/cluster-issuer: letsencrypt + +chatUis: + - name: safe + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo/chat-ui + tagversion: latest + agentUrl: /safe-agent + ingress: + enabled: false + className: "nginx" + apiDomainName: "" + domainPrefix: "chat-safe" + annotations: + cert-manager.io/cluster-issuer: letsencrypt + - name: compromised + docker: + registry: ghcr.io/outshift-open + image: outshift-casa/demo/chat-ui + tagversion: latest + agentUrl: /compromised-agent + ingress: + enabled: false + className: "nginx" + apiDomainName: "" + domainPrefix: "chat-compromised" + annotations: + cert-manager.io/cluster-issuer: letsencrypt llmCredentials: - apiBaseUrl: "" - apiKey: "" + apiBaseUrl: "" + apiKey: "" diff --git a/deployments/helm/casa-runtime/templates/ui-explorer/configmap.yaml b/deployments/helm/casa-runtime/templates/ui-explorer/configmap.yaml index 8bd5b9b0..9a054dfc 100644 --- a/deployments/helm/casa-runtime/templates/ui-explorer/configmap.yaml +++ b/deployments/helm/casa-runtime/templates/ui-explorer/configmap.yaml @@ -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; diff --git a/deployments/helm/casa-runtime/values.yaml b/deployments/helm/casa-runtime/values.yaml index 2ef0b66f..07aa29fa 100644 --- a/deployments/helm/casa-runtime/values.yaml +++ b/deployments/helm/casa-runtime/values.yaml @@ -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. and + # enable authService.ingress so the browser calls the auth-service directly. apiProxyEnabled: true # ─── PostgreSQL (auth-service backend) ─────────────────────────────────────── diff --git a/scripts/dev/local-setup-standalone.sh b/scripts/dev/local-setup-standalone.sh index 17621e5d..004ca335 100755 --- a/scripts/dev/local-setup-standalone.sh +++ b/scripts/dev/local-setup-standalone.sh @@ -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" @@ -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 \ @@ -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' \ @@ -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' \ @@ -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 # --------------------------------------------------------------------------- @@ -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 @@ -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 "" diff --git a/scripts/local-setup-standalone-new.sh b/scripts/local-setup-standalone-new.sh new file mode 100755 index 00000000..db028e51 --- /dev/null +++ b/scripts/local-setup-standalone-new.sh @@ -0,0 +1,423 @@ +#!/usr/bin/env bash +# local-setup-standalone-new.sh — Self-contained minikube bootstrap for CASA banking demo +# No external files required — all helm values are inlined. +# Uses nginx ingress controller directly (no Python proxy or pfctl needed). +# +# Usage: +# bash scripts/local-setup-standalone-new.sh # banking demo (Istio + sidecars) +# bash scripts/local-setup-standalone-new.sh --no-istio # no-Istio mode (no enforcement) +# bash scripts/local-setup-standalone-new.sh reset # wipe data and reinstall +# bash scripts/local-setup-standalone-new.sh --no-istio reset # wipe + reinstall without Istio +# +# Prerequisites: minikube, istioctl, helm, kubectl, docker, crane +# brew install minikube istioctl helm kubectl crane +# Prerequisites (--no-istio only): minikube, helm, kubectl, docker +# brew install minikube helm kubectl +set -euo pipefail + +# --------------------------------------------------------------------------- +# Required env vars (export before running): +# CASA_LLM_HOST OpenAI-compatible API hostname (e.g. litellm.prod.outshift.ai) +# CASA_LLM_API_KEY API key for the LLM service +# +# Optional env vars: +# CASA_LLM_MODEL_ID LLM model for auth checks (default: bedrock/global.anthropic.claude-sonnet-4-6) +# CASA_LLM_PIPELINE_MODEL_ID Pipeline model (default: azure/gpt-4o) +# CASA_LLM_JWT_TOKEN JWT token for LLM service (defaults to CASA_LLM_API_KEY) +# --------------------------------------------------------------------------- +: "${CASA_LLM_HOST:?CASA_LLM_HOST must be set (e.g. litellm.prod.outshift.ai)}" +: "${CASA_LLM_API_KEY:?CASA_LLM_API_KEY must be set}" + +CASA_LLM_MODEL_ID="${CASA_LLM_MODEL_ID:-bedrock/global.anthropic.claude-sonnet-4-6}" +CASA_LLM_PIPELINE_MODEL_ID="${CASA_LLM_PIPELINE_MODEL_ID:-azure/gpt-4o}" +CASA_LLM_JWT_TOKEN="${CASA_LLM_JWT_TOKEN:-$CASA_LLM_API_KEY}" +CASA_LLM_API_BASE_URL="http://${CASA_LLM_HOST}" + +NAMESPACE="casa-dev" + +# --------------------------------------------------------------------------- +# Parse flags +# --------------------------------------------------------------------------- +WITH_ISTIO=true +DESIRED_MEMORY=7168 +POSITIONAL_ARGS=() +for arg in "$@"; do + case "$arg" in + --no-istio) WITH_ISTIO=false ;; + *) POSITIONAL_ARGS+=("$arg") ;; + esac +done +set -- "${POSITIONAL_ARGS[@]+"${POSITIONAL_ARGS[@]}"}" + +log() { echo ""; echo "==> $*"; } + +# --------------------------------------------------------------------------- +# Reset mode: wipe helm releases + PVCs then continue with fresh install +# --------------------------------------------------------------------------- +if [[ "${1:-}" == "reset" ]]; then + log "Reset — stripping MAS finalizers to unblock deletion" + kubectl get multiagentsystems.casa.io -n "$NAMESPACE" -o name 2>/dev/null | \ + xargs -I{} kubectl patch {} -n "$NAMESPACE" --type=json \ + -p='[{"op":"remove","path":"/metadata/finalizers"}]' 2>/dev/null || true + + log "Reset — stripping CASAPolicy finalizers to unblock deletion" + kubectl get casapolicies.casa.io -n "$NAMESPACE" -o name 2>/dev/null | \ + xargs -I{} kubectl patch {} -n "$NAMESPACE" --type=json \ + -p='[{"op":"remove","path":"/metadata/finalizers"}]' 2>/dev/null || true + + log "Reset — uninstalling helm releases" + helm uninstall casa-banking -n "$NAMESPACE" 2>/dev/null || true + helm uninstall casa-dev -n "$NAMESPACE" 2>/dev/null || true + + log "Reset — deleting PVCs" + kubectl delete pvc --all -n "$NAMESPACE" 2>/dev/null || true + + log "Reset — done, continuing with fresh install…" +fi + +# --------------------------------------------------------------------------- +# 1. Start Minikube +# --------------------------------------------------------------------------- +log "Step 1 — Start Minikube" +CURRENT_MEMORY=$(python3 -c "import json; d=json.load(open('$HOME/.minikube/machines/minikube/config.json')); print(d.get('MemSize',0))" 2>/dev/null || echo "0") +if [ "$CURRENT_MEMORY" != "0" ] && [ "$CURRENT_MEMORY" != "$DESIRED_MEMORY" ]; then + echo " memory mismatch (current: ${CURRENT_MEMORY}MB, desired: ${DESIRED_MEMORY}MB) — deleting cluster" + minikube delete 2>/dev/null || true +fi + +if minikube status --format='{{.Host}}' 2>/dev/null | grep -q "Running"; then + echo " minikube already running with ${DESIRED_MEMORY}MB, skipping start" +else + if $WITH_ISTIO; then + minikube start \ + --driver=docker \ + --memory=$DESIRED_MEMORY \ + --cpus=6 \ + --addons=registry,ingress + else + minikube start \ + --driver=docker \ + --memory=$DESIRED_MEMORY \ + --cpus=6 \ + --addons=ingress + fi +fi + +minikube addons enable ingress 2>/dev/null || true + +if $WITH_ISTIO; then + minikube addons enable registry 2>/dev/null || true + log "Step 1 — Port-forward in-cluster registry (localhost:5000)" + pkill -f "kubectl port-forward.*kube-system.*svc/registry" 2>/dev/null || true + kubectl port-forward -n kube-system svc/registry 5000:80 & + sleep 2 +fi + +# --------------------------------------------------------------------------- +# 2. Install Istio (--with-istio only) +# --------------------------------------------------------------------------- +if $WITH_ISTIO; then + log "Step 2 — Install Istio (minimal profile)" + istioctl install --set profile=minimal -y +else + log "Step 2 — Skipping Istio install (--no-istio mode)" +fi + +# --------------------------------------------------------------------------- +# 3. Create namespace +# --------------------------------------------------------------------------- +log "Step 3 — Create namespace $NAMESPACE" +kubectl create namespace "$NAMESPACE" 2>/dev/null || echo " namespace already exists" +if $WITH_ISTIO; then + kubectl label namespace "$NAMESPACE" istio-injection=enabled --overwrite +fi + +# --------------------------------------------------------------------------- +# 4. Build Docker images +# --------------------------------------------------------------------------- +log "Step 4 — Point shell at minikube Docker daemon" +eval "$(minikube docker-env)" + +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 \ + --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 shared demo images (mcp + chat-ui, used by banking demo)" +docker build -f demo/src/mcp/Dockerfile -t demo-mcp:local demo/src/mcp +docker build -f demo/src/chat-ui/Dockerfile -t demo-chat-ui:local demo/src/chat-ui + +log "Step 4 — Build banking demo images" +docker build -f demo_new/src/banking-assistant/Dockerfile -t demo-new-banking-assistant:local demo_new/src/banking-assistant +docker build -f demo_new/src/banking-data-agent/Dockerfile -t demo-new-banking-data-agent:local demo_new/src/banking-data-agent +docker build -f demo_new/src/payments-agent/Dockerfile -t demo-new-banking-payments-agent:local demo_new/src/payments-agent +docker build -f demo_new/src/banking-beneficiary-agent/Dockerfile -t demo-new-banking-beneficiary-agent:local demo_new/src/banking-beneficiary-agent + +if $WITH_ISTIO; then + log "Step 4 — Build and push WasmPlugin OCI images" + docker build -f sidecar/llm_proxy/Dockerfile -t llm-proxy:local sidecar/llm_proxy + docker build -f sidecar/traceparent_injector/Dockerfile -t traceparent-injector:local sidecar/traceparent_injector + + docker save llm-proxy:local -o /tmp/llm-proxy.tar + docker save traceparent-injector:local -o /tmp/traceparent-injector.tar + crane push --insecure /tmp/llm-proxy.tar localhost:5000/llm-proxy:local + crane push --insecure /tmp/traceparent-injector.tar localhost:5000/traceparent-injector:local + rm /tmp/llm-proxy.tar /tmp/traceparent-injector.tar +else + log "Step 4 — Skipping WasmPlugin builds (--no-istio mode)" +fi + +# --------------------------------------------------------------------------- +# 5. Deploy control plane +# --------------------------------------------------------------------------- +log "Step 5 — Add helm repositories" +helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts 2>/dev/null || true +helm repo add jaegertracing https://jaegertracing.github.io/helm-charts 2>/dev/null || true +helm repo add bitnami https://charts.bitnami.com/bitnami 2>/dev/null || true +helm repo update + +log "Step 5 — Build helm dependencies" +if $WITH_ISTIO; then + helm dependency build deployments/helm/sidecar +fi +helm dependency build deployments/helm/casa-runtime + +log "Step 5 — Install/upgrade casa-runtime" +HELM_SIDECAR_ARGS=() +if $WITH_ISTIO; then + HELM_SIDECAR_ARGS=( + --set sidecar.enabled=true + --set sidecar.authServerHost="" + --set sidecar.image.repository=ext-auth-service + --set sidecar.image.tag=local + --set sidecar.image.pullPolicy=Never + --set sidecar.llm_proxy.image.repository=registry.kube-system.svc.cluster.local/llm-proxy + --set sidecar.llm_proxy.image.tag=local + --set sidecar.llm_proxy.image.pullPolicy=IfNotPresent + --set sidecar.traceparent_injector.image.repository=registry.kube-system.svc.cluster.local/traceparent-injector + --set sidecar.traceparent_injector.image.tag=local + --set sidecar.traceparent_injector.image.pullPolicy=IfNotPresent + ) +else + HELM_SIDECAR_ARGS=(--set sidecar.enabled=false) +fi + +helm upgrade --install casa-dev \ + deployments/helm/casa-runtime \ + -n "$NAMESPACE" \ + --create-namespace \ + --set authService.image.repository=casa-auth-server \ + --set authService.image.tag=local \ + --set authService.image.pullPolicy=Never \ + --set authService.database.password=postgres \ + --set authService.idp.adminPassword=admin \ + --set "authService.openai.apiBaseUrl=${CASA_LLM_API_BASE_URL}" \ + --set "authService.openai.jwtToken=${CASA_LLM_JWT_TOKEN}" \ + --set "authService.openai.llmApiBaseUrl=${CASA_LLM_API_BASE_URL}" \ + --set "authService.openai.llmApiKey=${CASA_LLM_API_KEY}" \ + --set "authService.openai.modelId=${CASA_LLM_MODEL_ID}" \ + --set "authService.openai.pipelineModelId=${CASA_LLM_PIPELINE_MODEL_ID}" \ + --set authService.externalSecrets.enabled=false \ + --set authService.ingress.enabled=true \ + --set authService.ingress.className=nginx \ + --set authService.ingress.apiDomainName=casa.outshift.ai \ + --set authService.ingress.domainPrefix=api \ + --set uiExplorer.image.repository=casa-auth-server-ui \ + --set uiExplorer.image.tag=local \ + --set uiExplorer.image.pullPolicy=Never \ + --set uiExplorer.ingress.enabled=true \ + --set uiExplorer.ingress.className=nginx \ + --set uiExplorer.ingress.apiDomainName=casa.outshift.ai \ + --set uiExplorer.ingress.domainPrefix=explorer \ + --set uiExplorer.nginx.apiProxyEnabled=false \ + --set keycloak.image.repository=casa-auth-server-keycloak \ + --set keycloak.image.tag=local \ + --set keycloak.image.pullPolicy=Never \ + --set keycloak.hostname=localhost \ + --set keycloak.hostnamePort=8080 \ + --set operator.image.repository=casa-operator \ + --set operator.image.tag=local \ + --set operator.image.pullPolicy=Never \ + --set postgresAuth.persistence.storageClass="" \ + --set postgresKeycloak.persistence.storageClass="" \ + "${HELM_SIDECAR_ARGS[@]}" + +# --------------------------------------------------------------------------- +# Wait for control plane pods to be ready +# --------------------------------------------------------------------------- +log "Waiting for control plane pods to be Ready (timeout 10 min)…" +kubectl wait pod \ + --for=condition=Ready \ + --selector='app.kubernetes.io/instance=casa-dev' \ + -n "$NAMESPACE" \ + --timeout=600s + +# --------------------------------------------------------------------------- +# 6. Deploy banking demo (demo_new) +# --------------------------------------------------------------------------- +log "Step 6 — Install/upgrade banking demo" +helm upgrade --install casa-banking \ + demo_new/helm \ + -n "$NAMESPACE" \ + --set bankingAssistantSafe.docker.registry="" \ + --set bankingAssistantSafe.docker.image=demo-new-banking-assistant \ + --set bankingAssistantSafe.tagversion=local \ + --set bankingAssistantCompromised.docker.registry="" \ + --set bankingAssistantCompromised.docker.image=demo-new-banking-assistant \ + --set bankingAssistantCompromised.tagversion=local \ + --set bankingDataAgentA.docker.registry="" \ + --set bankingDataAgentA.docker.image=demo-new-banking-data-agent \ + --set bankingDataAgentA.tagversion=local \ + --set bankingDataAgentB.docker.registry="" \ + --set bankingDataAgentB.docker.image=demo-new-banking-data-agent \ + --set bankingDataAgentB.tagversion=local \ + --set bankingPaymentsAgentA.docker.registry="" \ + --set bankingPaymentsAgentA.docker.image=demo-new-banking-payments-agent \ + --set bankingPaymentsAgentA.tagversion=local \ + --set bankingPaymentsAgentB.docker.registry="" \ + --set bankingPaymentsAgentB.docker.image=demo-new-banking-payments-agent \ + --set bankingPaymentsAgentB.tagversion=local \ + --set bankingBeneficiaryAgent.docker.registry="" \ + --set bankingBeneficiaryAgent.docker.image=demo-new-banking-beneficiary-agent \ + --set bankingBeneficiaryAgent.tagversion=local \ + --set bankingBeneficiaryAgentCompromised.docker.registry="" \ + --set bankingBeneficiaryAgentCompromised.docker.image=demo-new-banking-beneficiary-agent \ + --set bankingBeneficiaryAgentCompromised.tagversion=local \ + --set mcpA.docker.registry="" \ + --set mcpA.docker.image=demo-mcp \ + --set mcpA.tagversion=local \ + --set mcpB.docker.registry="" \ + --set mcpB.docker.image=demo-mcp \ + --set mcpB.tagversion=local \ + --set 'chatUis[0].name=safe' \ + --set 'chatUis[0].docker.registry=' \ + --set 'chatUis[0].docker.image=demo-chat-ui' \ + --set 'chatUis[0].tagversion=local' \ + --set 'chatUis[0].agentUrl=/safe-agent' \ + --set 'chatUis[0].ingress.enabled=true' \ + --set 'chatUis[0].ingress.className=nginx' \ + --set 'chatUis[0].ingress.apiDomainName=casa.outshift.ai' \ + --set 'chatUis[0].ingress.domainPrefix=banking-safe' \ + --set 'chatUis[1].name=compromised' \ + --set 'chatUis[1].docker.registry=' \ + --set 'chatUis[1].docker.image=demo-chat-ui' \ + --set 'chatUis[1].tagversion=local' \ + --set 'chatUis[1].agentUrl=/compromised-agent' \ + --set 'chatUis[1].ingress.enabled=true' \ + --set 'chatUis[1].ingress.className=nginx' \ + --set 'chatUis[1].ingress.apiDomainName=casa.outshift.ai' \ + --set 'chatUis[1].ingress.domainPrefix=banking-compromised' \ + --set "llmCredentials.apiBaseUrl=${CASA_LLM_API_BASE_URL}" \ + --set "llmCredentials.apiKey=${CASA_LLM_API_KEY}" \ + --set masSafe.name="CASA Banking Demo Safe" \ + --set 'masSafe.enabledToolChecks[0]=DETERMINISTIC_TOOL_SELECTED' \ + --set 'masSafe.enabledToolChecks[1]=AI_POWERED_TOOL_MATCH' \ + --set "masSafe.llm_host=${CASA_LLM_HOST}" \ + --set masCompromised.name="CASA Banking Demo Compromised" \ + --set 'masCompromised.enabledToolChecks[0]=DETERMINISTIC_TOOL_SELECTED' \ + --set 'masCompromised.enabledToolChecks[1]=AI_POWERED_TOOL_MATCH' \ + --set "masCompromised.llm_host=${CASA_LLM_HOST}" + +# --------------------------------------------------------------------------- +# 6b. Patch ingress annotations (minikube-specific buffer/timeout tuning) +# --------------------------------------------------------------------------- +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-banking-chat-ui-safe \ + casa-banking-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 +# --------------------------------------------------------------------------- +log "Step 7 — Pod status" +kubectl get pods -n "$NAMESPACE" + +log "Step 7 — MultiAgentSystem status" +kubectl get multiagentsystems.casa.io -n "$NAMESPACE" 2>/dev/null || echo " (no MAS resources yet)" + +log "Step 7 — CASAPolicy status" +kubectl get casapolicies.casa.io -n "$NAMESPACE" 2>/dev/null || echo " (no CASAPolicy resources yet)" + +# --------------------------------------------------------------------------- +# Wait for all pods to be ready +# --------------------------------------------------------------------------- +log "Waiting for all pods to be Ready (timeout 5 min)…" +kubectl wait pod \ + --for=condition=Ready \ + --all \ + -n "$NAMESPACE" \ + --timeout=300s + +# --------------------------------------------------------------------------- +# 8. Port-forwards +# --------------------------------------------------------------------------- +log "Step 8 — Starting port-forwards" + +# Cache sudo credentials upfront (needed for port 80 binding + /etc/hosts) +sudo -v + +pkill -f "kubectl port-forward.*$NAMESPACE" 2>/dev/null || true +sudo pkill -f "kubectl port-forward.*ingress-nginx" 2>/dev/null || true +sleep 1 + +kubectl port-forward -n "$NAMESPACE" svc/casa-dev-auth-service 8000:8000 & +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 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 api.casa.outshift.ai banking-safe.casa.outshift.ai banking-compromised.casa.outshift.ai" +if grep -q "casa.outshift.ai" /etc/hosts; then + sudo sed -i '' '/casa\.outshift\.ai/d' /etc/hosts +fi +echo "$HOSTS_LINE" | sudo -n tee -a /etc/hosts > /dev/null +echo " /etc/hosts updated" + +echo "" +echo "Port-forwards started (background jobs):" +echo " Auth server API → http://localhost:8000" +echo " Keycloak → http://localhost:8080" +echo " Jaeger traces → http://localhost:16686" +echo "" +echo "UIs available via nginx ingress (port 80):" +echo " CASA Explorer UI → http://explorer.casa.outshift.ai" +echo " Auth API → http://api.casa.outshift.ai" +echo " Banking safe chat UI → http://banking-safe.casa.outshift.ai" +echo " Banking compromised UI → http://banking-compromised.casa.outshift.ai" +echo "" +echo "Done. Run 'jobs' to see background port-forwards." diff --git a/src/casa_auth_server/telemetry/tracer_repository.py b/src/casa_auth_server/telemetry/tracer_repository.py index 04616966..f4e014d9 100644 --- a/src/casa_auth_server/telemetry/tracer_repository.py +++ b/src/casa_auth_server/telemetry/tracer_repository.py @@ -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 @@ -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."""