diff --git a/README.md b/README.md index db75632..b90a604 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Run the full stack locally with Docker: ```bash git clone https://github.com/ParleSec/ProtocolSoup.git cd ProtocolSoup/docker -docker compose up -d +docker compose up -d --build ``` Then open: diff --git a/backend/cmd/gateway/main.go b/backend/cmd/gateway/main.go index 125ea21..8a8f062 100644 --- a/backend/cmd/gateway/main.go +++ b/backend/cmd/gateway/main.go @@ -12,11 +12,28 @@ import ( "github.com/ParleSec/ProtocolSoup/internal/core" "github.com/ParleSec/ProtocolSoup/internal/gateway" + "github.com/ParleSec/ProtocolSoup/internal/palette" ) func main() { cfg := core.LoadConfig() + var paletteSvc *palette.Service + if cfg.PaletteDBPath != "" { + svc, err := palette.NewService(cfg.PaletteDBPath) + if err != nil { + if cfg.IsProduction() { + log.Fatalf("Failed to load palette index at %s: %v", cfg.PaletteDBPath, err) + } + log.Printf("Palette service disabled: %v", err) + } else { + paletteSvc = svc + stats := svc.Stats() + log.Printf("Palette service initialized from %s (%d artefacts, index v%s)", + cfg.PaletteDBPath, stats.ArtefactCount, stats.IndexVersion) + } + } + upstreams := []gateway.UpstreamConfig{ {Name: "federation", BaseURL: strings.TrimSpace(os.Getenv("FEDERATION_SERVICE_URL"))}, {Name: "scim", BaseURL: strings.TrimSpace(os.Getenv("SCIM_SERVICE_URL"))}, @@ -33,6 +50,7 @@ func main() { StartupRetryInitial: envDuration("GATEWAY_STARTUP_RETRY_INITIAL", 2*time.Second), StartupRetryMax: envDuration("GATEWAY_STARTUP_RETRY_MAX", 30*time.Second), RequestTimeout: envDuration("GATEWAY_REQUEST_TIMEOUT", 5*time.Second), + Palette: paletteSvc, }) if err != nil { log.Fatalf("Failed to initialize gateway: %v", err) diff --git a/backend/internal/gateway/gateway.go b/backend/internal/gateway/gateway.go index 6ad7284..a61e22d 100644 --- a/backend/internal/gateway/gateway.go +++ b/backend/internal/gateway/gateway.go @@ -15,6 +15,7 @@ import ( "sync" "time" + "github.com/ParleSec/ProtocolSoup/internal/palette" "github.com/go-chi/chi/v5" "github.com/go-chi/cors" ) @@ -29,6 +30,9 @@ type Config struct { StartupRetryInitial time.Duration StartupRetryMax time.Duration RequestTimeout time.Duration + // Palette serves POST /api/palette/query from a local SQLite index. Nil + // omits the route (split deployments without a baked index). + Palette *palette.Service } // UpstreamConfig represents an upstream service. @@ -66,6 +70,8 @@ type Upstream struct { type Gateway struct { cfg Config + palette *palette.Service + client *http.Client upstreams map[string]*Upstream order []string @@ -119,7 +125,8 @@ func NewGateway(cfg Config) (*Gateway, error) { } return &Gateway{ - cfg: cfg, + cfg: cfg, + palette: cfg.Palette, client: &http.Client{ Timeout: cfg.RequestTimeout, }, @@ -161,6 +168,10 @@ func (g *Gateway) Router() http.Handler { r.Post("/lookingglass/decode", g.handleDecodeToken) r.Get("/lookingglass/sessions", g.handleListSessions) r.Get("/lookingglass/sessions/{id}", g.handleGetSession) + + if g.palette != nil { + r.Post("/palette/query", g.palette.Handler()) + } }) r.Get("/ws/lookingglass/{session}", g.handleLookingGlassWS) diff --git a/backend/internal/gateway/handlers.go b/backend/internal/gateway/handlers.go index 209d070..bc56b25 100644 --- a/backend/internal/gateway/handlers.go +++ b/backend/internal/gateway/handlers.go @@ -60,6 +60,9 @@ func (g *Gateway) handleAPIIndex(w http.ResponseWriter, r *http.Request) { "lookingglass": "/api/lookingglass", "lookingglass_ws": "/ws/lookingglass/{session}", } + if g.palette != nil { + endpoints["palette"] = "/api/palette/query" + } g.writeJSON(w, http.StatusOK, apiIndexResponse{ Service: "protocol-lens-gateway", diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index e2b0f01..9fb1d62 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,5 +1,7 @@ # Protocol Soup - Split Backend Services (Base) -# Run with: docker compose up -d +# Run with: docker compose up -d --build +# After pulling new code, always pass --build so frontend and gateway images +# are rebuilt from source (palette UI and /api/palette/query are baked in). # # This starts: # - Gateway (API aggregation + protocol routing) @@ -45,6 +47,7 @@ services: - SHOWCASE_LISTEN_ADDR=:8080 - SHOWCASE_BASE_URL=http://localhost:8080 - SHOWCASE_CORS_ORIGINS=http://localhost:3000,http://localhost:5173 + - SHOWCASE_PALETTE_DB=/app/palette.db - FEDERATION_SERVICE_URL=http://federation-service:8080 - SCIM_SERVICE_URL=http://scim-service:8080 - SSF_SERVICE_URL=http://ssf-service:8080 @@ -177,6 +180,7 @@ services: NEXT_PUBLIC_WS_BASE_URL: ws://localhost:8080 # For using published GHCR images, comment 'build:' above and uncomment: # image: ghcr.io/parlesec/protocolsoup-frontend:latest + image: protocol-lens-frontend:latest container_name: protocol-showcase-frontend ports: - "3000:3000" diff --git a/docs/starlight/src/content/docs/deploy/deployment-models.mdx b/docs/starlight/src/content/docs/deploy/deployment-models.mdx index b1bd189..ca24a9a 100644 --- a/docs/starlight/src/content/docs/deploy/deployment-models.mdx +++ b/docs/starlight/src/content/docs/deploy/deployment-models.mdx @@ -11,11 +11,13 @@ Run the complete ProtocolSoup experience with all services. ```bash cd docker -docker compose up -d +docker compose up -d --build ``` **Services started:** frontend, gateway, federation-service, scim-service, ssf-service +The gateway image ships the [palette content index](/deploy/palette-index/) at `/app/palette.db` and serves `POST /api/palette/query` for homepage search and **cmd+K**. Rebuild images after pulling new code (`--build`); `docker compose up -d` alone reuses cached layers and can leave you on an older UI. + **Add SPIFFE:** ```bash diff --git a/docs/starlight/src/content/docs/start-here/quickstart.mdx b/docs/starlight/src/content/docs/start-here/quickstart.mdx index 116ea3d..b730c11 100644 --- a/docs/starlight/src/content/docs/start-here/quickstart.mdx +++ b/docs/starlight/src/content/docs/start-here/quickstart.mdx @@ -16,7 +16,7 @@ Run the frontend, gateway, federation, SCIM, and SSF services together. ```bash cd docker -docker compose up -d +docker compose up -d --build ``` This starts five services: diff --git a/frontend/src/components/common/LayoutHeader.client.tsx b/frontend/src/components/common/LayoutHeader.client.tsx index 285acf5..f3976ae 100644 --- a/frontend/src/components/common/LayoutHeader.client.tsx +++ b/frontend/src/components/common/LayoutHeader.client.tsx @@ -56,30 +56,15 @@ export function LayoutHeader() { <>
-
- - 🍜 - Protocol Soup - +
+
+ + 🍜 + Protocol Soup + +
-
@@ -166,19 +189,6 @@ export function LayoutHeader() {
- {showSearchChip && ( - - )} {navItems.map((item) => { const isActive = currentPath === item.path || (item.path !== '/' && currentPath.startsWith(item.path))