Skip to content
Merged
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
19 changes: 17 additions & 2 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ on:

env:
REGISTRY_GHCR: ghcr.io
IMAGE_NAME: blues-expert-mcp
IMAGE_NAME_GHCR: blues-expert-mcp
REGISTRY_ECR: 660644769541.dkr.ecr.us-east-1.amazonaws.com
IMAGE_NAME_ECR: /blues-dev/blues-expert-mcp

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write

steps:
- name: Checkout repository
Expand All @@ -32,12 +35,24 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::660644769541:role/blues-expert-mcp-github
role-session-name: GitHubActions
aws-region: us-east-1
audience: sts.amazonaws.com

- name: Log in to Amazon ECR
uses: aws-actions/amazon-ecr-login@v2

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY_GHCR }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
${{ env.REGISTRY_GHCR }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME_GHCR }}
${{ env.REGISTRY_ECR }}${{ env.IMAGE_NAME_ECR }}
tags: |
type=ref,event=branch
type=ref,event=pr
Expand Down
51 changes: 42 additions & 9 deletions blues-expert/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"crypto/subtle"
"flag"
"log"
"net/http"
Expand All @@ -22,6 +23,36 @@ func init() {
flag.StringVar(&envFilePath, "env", "", "Path to .env file to load environment variables")
}

func withBasicAuth(handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
username := os.Getenv("LOGS_AUTH_USER")
password := os.Getenv("LOGS_AUTH_PASS")

if username == "" || password == "" {
log.Printf("Warning: LOGS_AUTH_USER or LOGS_AUTH_PASS not set, logging endpoints are unprotected")
handler(w, r)
return
}

user, pass, ok := r.BasicAuth()
if !ok {
w.Header().Set("WWW-Authenticate", `Basic realm="Logging Endpoints"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}

// Use constant-time comparison to prevent timing attacks
if subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 ||
subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="Logging Endpoints"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}

handler(w, r)
}
}

func main() {
flag.Parse()

Expand Down Expand Up @@ -97,12 +128,14 @@ func main() {
// Metrics endpoint
mux.Handle("/metrics", promhttp.Handler())

// Logging endpoints
loggingEnabled := os.Getenv("ENABLE_LOGGING_ENDPOINTS") != ""
// Logging endpoints - enabled if authentication credentials are provided
logsAuthUser := os.Getenv("LOGS_AUTH_USER")
logsAuthPass := os.Getenv("LOGS_AUTH_PASS")
loggingEnabled := logsAuthUser != "" && logsAuthPass != ""
if loggingEnabled {
mux.HandleFunc("/logs", lib.LogsHandler)
mux.HandleFunc("/logs/stream", lib.LogsStreamHandler)
mux.HandleFunc("/logs/stats", lib.LogsStatsHandler)
mux.HandleFunc("/logs", withBasicAuth(lib.LogsHandler))
mux.HandleFunc("/logs/stream", withBasicAuth(lib.LogsStreamHandler))
mux.HandleFunc("/logs/stats", withBasicAuth(lib.LogsStatsHandler))
}

// Route all other requests to the MCP server
Expand All @@ -124,11 +157,11 @@ func main() {
log.Printf("Metrics available at /metrics")

if loggingEnabled {
log.Printf("Logs available at /logs")
log.Printf("Logs streaming (Loki) at /logs/stream")
log.Printf("Logs buffer stats at /logs/stats")
log.Printf("Logs available at /logs (requires basic auth)")
log.Printf("Logs streaming (Loki) at /logs/stream (requires basic auth)")
log.Printf("Logs buffer stats at /logs/stats (requires basic auth)")
} else {
log.Printf("Logging endpoints disabled (set ENABLE_LOGGING_ENDPOINTS to enable)")
log.Printf("Logging endpoints disabled (set credentials to enable)")
}

// Start HTTP server with our custom multiplexer
Expand Down