Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
0a8e462
Add Netflix AWS re:Invent 2023 video on database migrations
jrepp Nov 17, 2025
0116081
Add MEMO-083 Phase 2 Vault integration implementation plan
jrepp Nov 17, 2025
6c818de
Implement Week 1: Core Vault Infrastructure (pkg/authz foundation)
jrepp Nov 17, 2025
2fdebe8
Implement Week 2: Credential Lifecycle Management
jrepp Nov 17, 2025
fe0e29e
Implement Week 3: Token Validation with JWKS and Caching
jrepp Nov 17, 2025
734a612
Add Session Manager for complete JWT to Vault to credentials lifecycl…
jrepp Nov 17, 2025
ec5eded
Add service identity authentication with K8s and AWS support (Week 5)
jrepp Nov 17, 2025
b4c261f
Add Week 6: Integration testing, Vault testcontainer, and operator do…
jrepp Nov 18, 2025
cf764ea
Add MEMO-086: Pattern Runner SessionManager Integration Guide
jrepp Nov 18, 2025
7c5c9b1
Add composable pattern architecture with slot-based configuration
jrepp Nov 18, 2025
157e660
Add configuration parser for composable pattern architecture
jrepp Nov 18, 2025
ee2d610
Update MEMO-086 with implementation status and progress tracking
jrepp Nov 18, 2025
f7e4e19
Add TokenValidator interface for testability and fix test mocks
jrepp Nov 18, 2025
c6eda0a
Add MEMO-087 tracking composable patterns implementation progress
jrepp Nov 18, 2025
ef847cb
Fix MEMO-087 UUID format for validation
jrepp Nov 18, 2025
735a82d
Update MEMO-087 with verified config parser test results
jrepp Nov 18, 2025
ac499c9
Add Go workspace and working config package integration test
jrepp Nov 18, 2025
2019365
Add comprehensive code review and loader tests (92.1% coverage)
jrepp Nov 18, 2025
b3d9d4c
Add Week 2 code quality improvements to config package
jrepp Nov 18, 2025
3f25719
Update MEMO-088 with Week 2 completion status
jrepp Nov 18, 2025
39038d2
Add session middleware for pattern runner authentication
jrepp Nov 18, 2025
63141c8
Add comprehensive session middleware tests and coverage analysis
jrepp Nov 18, 2025
a547a99
Add session middleware integration to KeyValue pattern runner
jrepp Nov 18, 2025
25b4bdd
Add Phase 2 Vault integration to KeyValue pattern runner
jrepp Nov 18, 2025
9266b29
Add protobuf-first namespace onboarding with composable patterns
jrepp Nov 18, 2025
6ebee48
Refactor to unified namespace model (remove composable complexity)
jrepp Nov 18, 2025
cf4e221
Fix protobuf import cycle by moving options to prism.common package
jrepp Nov 18, 2025
e2840d4
Update changelog with protobuf import cycle resolution
jrepp Nov 18, 2025
7f8ac97
Document pkg/config refactoring plan in MEMO-092
jrepp Nov 18, 2025
36dbb0c
Add protobuf-first YAML loader for namespace configurations
jrepp Nov 18, 2025
65234a9
Update changelog with Phase 2 completion
jrepp Nov 18, 2025
1ed4e85
Implement CreateNamespace RPC handler with pattern selection and back…
jrepp Nov 18, 2025
c9dd345
Update changelog with Phase 3 completion
jrepp Nov 18, 2025
ef25799
Fix compilation errors after protobuf structure changes
jrepp Nov 18, 2025
1e153cf
Complete Phase 3 auth integration for Consumer and Producer patterns …
jrepp Nov 19, 2025
f8047f0
Fix missing blank lines before code fences in MEMO-092
jrepp Nov 19, 2025
b18c0ff
Fix test compilation errors and update module dependencies
jrepp Nov 19, 2025
200690e
Fix findProjectRoot logic and add keyvalue-runner to workspace
jrepp Nov 19, 2025
f43653d
Add comprehensive tests for pkg/plugin configuration parsing
jrepp Nov 19, 2025
3bca9f8
Add comprehensive tests for pkg/plugin backend and dataplane
jrepp Nov 19, 2025
c0790a7
Add comprehensive tests for token validator
jrepp Nov 19, 2025
940a02f
Add comprehensive tests for NATS driver queue operations
jrepp Nov 19, 2025
a713a66
Add comprehensive tests for pkg/drivers/sqlite achieving 87% coverage
jrepp Nov 19, 2025
b8f0cc8
Add comprehensive tests for pkg/drivers/redis achieving 86.7% coverage
jrepp Nov 19, 2025
a2091bb
Add tests for patterns/keyvalue improving coverage from 33.6% to 40.7%
jrepp Nov 19, 2025
137f760
Add comprehensive tests for patterns/producer from 57.8% to 75.9%
jrepp Nov 19, 2025
077948e
Add comprehensive tests for patterns/mailbox from 66.9% to 82.4%
jrepp Nov 19, 2025
b8ba0ef
Fix integration tests to use proxy instead of direct backend access
jrepp Nov 19, 2025
ccb6755
Fix Go workspace configuration and improve Docker build performance
jrepp Nov 19, 2025
8f5175b
Fix Docker build and Go workspace configuration issues
jrepp Nov 20, 2025
002b45c
Add tests/testing/testrunner to go.work
jrepp Nov 20, 2025
e1274ad
Merge origin/main
jrepp Nov 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ LICENSE
# Build artifacts (exclude, will be built in container)
build/
target/
**/target/
dist/
clients/
*.o
*.so
*.dylib
Expand Down
Binary file added .playwright-mcp/dropdown-still-not-working.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/mobile-375-code-blocks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/mobile-375-code-syntax.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/mobile-375-dropdown-open.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/mobile-375-home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/mobile-375-menu-open.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/mobile-375-toml-code.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/navbar-1100px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/navbar-1400px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/navbar-dropdown-issue.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/new-hero-desktop-1920.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/new-hero-mobile-375.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/tablet-768-home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/tags-dropdown-working.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .playwright-mcp/tech-dropdown-active.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# ============================================================================
# Stage 1: Base builder with all dependencies
# ============================================================================
FROM golang:1.24-alpine AS builder-base
FROM golang:1.25-alpine AS builder-base

# Install build dependencies (cached layer)
RUN apk add --no-cache \
Expand Down
176 changes: 176 additions & 0 deletions cmd/prism-admin/backend_assignment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package main

import (
"context"
"fmt"

configv1 "github.com/jrepp/prism-data-layer/pkg/plugin/gen/prism/config/v1"
)

// BackendAssigner implements Layer 4: Backend Assignment
// Assigns specific backend instances to pattern slots.
type BackendAssigner struct {
storage *Storage
}

// NewBackendAssigner creates a new backend assigner
func NewBackendAssigner(storage *Storage) *BackendAssigner {
return &BackendAssigner{
storage: storage,
}
}

// AssignBackends performs backend assignment for pattern slots.
//
// Layer 4 responsibilities (RFC-056):
// - Map slots to actual backend instances
// - Select backends based on requirements and availability
// - Generate slot bindings with connection info
// - Handle multi-tenancy and isolation requirements
//
// For now, this is a simple implementation that:
// 1. Creates default backend instances based on slot backend_type
// 2. Generates connection strings (localhost for dev)
// 3. Returns slot bindings ready for deployment
//
// Future enhancements:
// - Query backend registry for available backends
// - Select backends based on region, capacity, cost
// - Handle backend pooling and multi-tenancy
// - Generate dynamic credentials via Vault
// - Implement backend health checking
func (ba *BackendAssigner) AssignBackends(
ctx context.Context,
req *configv1.NamespaceRequest,
) ([]*configv1.SlotBinding, error) {
if req == nil {
return nil, fmt.Errorf("namespace request is nil")
}

var bindings []*configv1.SlotBinding

// Process each pattern's slots
for _, pattern := range req.Patterns {
// Process requires slots
for _, slot := range pattern.Requires {
binding, err := ba.createSlotBinding(ctx, req.Namespace, pattern.Name, slot)
if err != nil {
return nil, fmt.Errorf("pattern %s, slot %s: %w", pattern.Name, slot.Name, err)
}
bindings = append(bindings, binding)
}

// Process produces slots
for _, slot := range pattern.Produces {
binding, err := ba.createSlotBinding(ctx, req.Namespace, pattern.Name, slot)
if err != nil {
return nil, fmt.Errorf("pattern %s, slot %s: %w", pattern.Name, slot.Name, err)
}
bindings = append(bindings, binding)
}
}

return bindings, nil
}

// createSlotBinding creates a slot binding for a specific slot.
//
// This generates the backend connection configuration including:
// - Backend instance ID
// - Connection endpoint
// - Credential path (vault:// for dynamic credentials)
// - Status and metadata
func (ba *BackendAssigner) createSlotBinding(
ctx context.Context,
namespace string,
patternName string,
slot *configv1.Slot,
) (*configv1.SlotBinding, error) {
// Generate backend instance ID
backendID := fmt.Sprintf("%s-%s-%s", namespace, patternName, slot.Name)

// Get connection endpoint based on backend type
endpoint, err := ba.getBackendEndpoint(slot.BackendType)
if err != nil {
return nil, err
}

// Determine credential source
credentialSource := fmt.Sprintf(
"vault://secret/data/prism/%s/%s/%s",
namespace,
patternName,
slot.Name,
)
if slot.Config != nil && slot.Config.CredentialPath != "" {
credentialSource = slot.Config.CredentialPath
}

// Create slot binding
binding := &configv1.SlotBinding{
PatternName: patternName,
SlotName: slot.Name,
BackendId: backendID,
BackendEndpoint: endpoint,
CredentialSource: credentialSource,
}

return binding, nil
}

// getBackendEndpoint returns the connection endpoint for a backend type.
//
// This returns default local endpoints for development.
// In production, this would query a backend registry service.
func (ba *BackendAssigner) getBackendEndpoint(backendType configv1.BackendType) (string, error) {
switch backendType {
case configv1.BackendType_BACKEND_TYPE_REDIS:
return "localhost:6379", nil
case configv1.BackendType_BACKEND_TYPE_POSTGRES:
return "localhost:5432", nil
case configv1.BackendType_BACKEND_TYPE_KAFKA:
return "localhost:9092", nil
case configv1.BackendType_BACKEND_TYPE_NATS:
return "localhost:4222", nil
case configv1.BackendType_BACKEND_TYPE_NEPTUNE:
return "", fmt.Errorf("Neptune backend requires AWS configuration")
case configv1.BackendType_BACKEND_TYPE_SQLITE:
return "/tmp/prism.db", nil
case configv1.BackendType_BACKEND_TYPE_S3:
return "localhost:9000", nil // MinIO
case configv1.BackendType_BACKEND_TYPE_SQS:
return "", fmt.Errorf("SQS backend requires AWS configuration")
case configv1.BackendType_BACKEND_TYPE_MEMSTORE:
return "memory://", nil
default:
return "", fmt.Errorf("unsupported backend type: %v", backendType)
}
}

// ValidateBackendAvailability checks if requested backends are available.
//
// This would:
// - Check backend registry for availability
// - Verify region/zone requirements
// - Check capacity and resource limits
// - Validate backend version compatibility
//
// For now, we just verify that we can map to an endpoint.
func (ba *BackendAssigner) ValidateBackendAvailability(
ctx context.Context,
patterns []*configv1.Pattern,
) error {
for _, pattern := range patterns {
for _, slot := range pattern.Requires {
if _, err := ba.getBackendEndpoint(slot.BackendType); err != nil {
return fmt.Errorf("pattern %s, slot %s: %w", pattern.Name, slot.Name, err)
}
}
for _, slot := range pattern.Produces {
if _, err := ba.getBackendEndpoint(slot.BackendType); err != nil {
return fmt.Errorf("pattern %s, slot %s: %w", pattern.Name, slot.Name, err)
}
}
}
return nil
}
63 changes: 19 additions & 44 deletions cmd/prism-admin/control_plane.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,27 @@ import (

pb "github.com/jrepp/prism-data-layer/pkg/plugin/gen/prism"
adminpb "github.com/jrepp/prism-data-layer/pkg/plugin/gen/prism/admin"
configv1 "github.com/jrepp/prism-data-layer/pkg/plugin/gen/prism/config/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

// ControlPlaneService implements the ControlPlane gRPC service
type ControlPlaneService struct {
pb.UnimplementedControlPlaneServer
storage *Storage
partitions *PartitionManager
mu sync.RWMutex
storage *Storage
partitions *PartitionManager
namespaceHandler *NamespaceHandler
mu sync.RWMutex
}

// NewControlPlaneService creates a new control plane service
func NewControlPlaneService(storage *Storage) *ControlPlaneService {
partitions := NewPartitionManager()
return &ControlPlaneService{
storage: storage,
partitions: NewPartitionManager(),
storage: storage,
partitions: partitions,
namespaceHandler: NewNamespaceHandler(storage, partitions),
}
}

Expand Down Expand Up @@ -99,50 +103,21 @@ func (s *ControlPlaneService) AssignNamespace(
}, nil
}

// CreateNamespace handles client-initiated namespace creation requests
// CreateNamespace handles unified namespace creation requests
// This implements the new protobuf-first namespace model with:
// - Multi-pattern composition
// - Slot-based backend dependencies
// - Session-aware patterns
// - Pattern selection (Layer 3)
// - Backend assignment (Layer 4)
func (s *ControlPlaneService) CreateNamespace(
ctx context.Context,
req *pb.CreateNamespaceRequest,
) (*pb.CreateNamespaceResponse, error) {
req *configv1.NamespaceRequest,
) (*configv1.NamespaceResponse, error) {
s.mu.Lock()
defer s.mu.Unlock()

fmt.Printf("[ControlPlane] CreateNamespace: namespace=%s, requesting_proxy=%s, principal=%s\n",
req.Namespace, req.RequestingProxy, req.Principal)

// Calculate partition ID for this namespace
partitionID := s.partitions.HashNamespace(req.Namespace)

// Find proxy assigned to this partition
// TODO: Query from storage - for now return error
var proxies []*adminpb.ProxyEntry
proxyID, err := s.partitions.GetProxyForPartitionFromSet(partitionID, proxies)
if err != nil {
return nil, status.Errorf(codes.FailedPrecondition,
"no proxy assigned to partition %d: %v", partitionID, err)
}

// Persist namespace in storage
ns := &Namespace{
Name: req.Namespace,
Description: fmt.Sprintf("Created via %s by %s", req.RequestingProxy, req.Principal),
}

if err := s.storage.CreateNamespace(ctx, ns); err != nil {
return nil, status.Errorf(codes.Internal, "failed to create namespace: %v", err)
}

fmt.Printf("[ControlPlane] Namespace created: %s → partition %d → proxy %s\n",
req.Namespace, partitionID, proxyID)

// TODO: Send NamespaceAssignment to the assigned proxy

return &pb.CreateNamespaceResponse{
Success: true,
Message: "Namespace created successfully",
AssignedPartition: partitionID,
AssignedProxy: proxyID,
}, nil
return s.namespaceHandler.CreateNamespace(ctx, req)
}

// Heartbeat receives periodic health updates from proxies
Expand Down
Loading